blob: efdbd4b67f409eb9e01b71db5ac89b156d9b937e [file] [log] [blame]
Jean-Paul Calderone8210b922013-02-09 09:03:18 -08001"""
2PRNG management routines, thin wrappers.
3
4See the file RATIONALE for a short explanation of why this module was written.
5"""
6
7import __builtin__
8
9from tls.c import api as _api
10
11# TODO Nothing tests the existence or use of this
12class Error(Exception):
13 pass
14
15
16_unspecified = object()
17
18def bytes(num_bytes):
19 """
20 Get some random bytes as a string.
21
22 :param num_bytes: The number of bytes to fetch
23 :return: A string of random bytes
24 """
25 if not isinstance(num_bytes, int):
26 raise TypeError("num_bytes must be an integer")
27
28 if num_bytes < 0:
29 raise ValueError("num_bytes must not be negative")
30
31 result_buffer = _api.new("char[]", num_bytes)
32 result_code = _api.RAND_bytes(result_buffer, num_bytes)
33 if result_code == -1:
34 raise Exception("zoops") # TODO
35 return _api.buffer(result_buffer)[:]
36
37
38
39def add(buffer, entropy):
40 """
41 Add data with a given entropy to the PRNG
42
43 :param buffer: Buffer with random data
44 :param entropy: The entropy (in bytes) measurement of the buffer
45 :return: None
46 """
47 if not isinstance(buffer, __builtin__.bytes):
48 raise TypeError("buffer must be a byte string")
49
50 if not isinstance(entropy, int):
51 raise TypeError("entropy must be an integer")
52
53 # TODO Nothing tests this call actually being made, or made properly.
54 _api.RAND_add(buffer, len(buffer), entropy)
55
56
57
58def seed(buffer):
59 """
60 Alias for rand_add, with entropy equal to length
61
62 :param buffer: Buffer with random data
63 :return: None
64 """
65 if not isinstance(buffer, __builtin__.bytes):
66 raise TypeError("buffer must be a byte string")
67
68 # TODO Nothing tests this call actually being made, or made properly.
69 _api.RAND_seed(buffer, len(buffer))
70
71
72
73def status():
74 """
75 Retrieve the status of the PRNG
76
77 :return: True if the PRNG is seeded enough, false otherwise
78 """
79 return _api.RAND_status()
80
81
82
83def egd(path, bytes=_unspecified):
84 """
85 Query an entropy gathering daemon (EGD) for random data and add it to the
86 PRNG. I haven't found any problems when the socket is missing, the function
87 just returns 0.
88
89 :param path: The path to the EGD socket
90 :param bytes: (optional) The number of bytes to read, default is 255
91 :returns: The number of bytes read (NB: a value of 0 isn't necessarily an
92 error, check rand.status())
93 """
94 if not isinstance(path, str):
95 raise TypeError("path must be a string")
96
97 if bytes is _unspecified:
98 bytes = 255
99 elif not isinstance(bytes, int):
100 raise TypeError("bytes must be an integer")
101
102 return _api.RAND_egd_bytes(path, bytes)
103
104
105
106def cleanup():
107 """
108 Erase the memory used by the PRNG.
109
110 :return: None
111 """
112 # TODO Nothing tests this call actually being made, or made properly.
113 _api.RAND_cleanup()
114
115
116
117def load_file(filename, maxbytes=_unspecified):
118 """
119 Seed the PRNG with data from a file
120
121 :param filename: The file to read data from
122 :param maxbytes: (optional) The number of bytes to read, default is
123 to read the entire file
124 :return: The number of bytes read
125 """
126 if not isinstance(filename, str):
127 raise TypeError("filename must be a string")
128
129 if maxbytes is _unspecified:
130 maxbytes = -1
131 elif not isinstance(maxbytes, int):
132 raise TypeError("maxbytes must be an integer")
133
134 return _api.RAND_load_file(filename, maxbytes)
135
136
137
138def write_file(filename):
139 """
140 Save PRNG state to a file
141
142 :param filename: The file to write data to
143 :return: The number of bytes written
144 """
145 if not isinstance(filename, str):
146 raise TypeError("filename must be a string")
147
148 return _api.RAND_write_file(filename)
149
150
151# TODO There are no tests for screen at all
152def screen():
153 """
154 Add the current contents of the screen to the PRNG state. Availability:
155 Windows.
156
157 :return: None
158 """
159 _api.RAND_screen()
160
161if getattr(_api, 'RAND_screen', None) is None:
162 del screen
163
164
165# TODO There are no tests for the RAND strings being loaded, whatever that
166# means.
167_api.ERR_load_RAND_strings()