blob: 82958547d5c6c828b541c7cca77785a8e1ee2c5f [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
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05009from cryptography.hazmat.backends.openssl import backend
10_lib = backend.lib
11_ffi = backend.ffi
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080012
13# TODO Nothing tests the existence or use of this
14class Error(Exception):
15 pass
16
17
18_unspecified = object()
19
20def bytes(num_bytes):
21 """
22 Get some random bytes as a string.
23
24 :param num_bytes: The number of bytes to fetch
25 :return: A string of random bytes
26 """
27 if not isinstance(num_bytes, int):
28 raise TypeError("num_bytes must be an integer")
29
30 if num_bytes < 0:
31 raise ValueError("num_bytes must not be negative")
32
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050033 result_buffer = _ffi.new("char[]", num_bytes)
34 result_code = _lib.RAND_bytes(result_buffer, num_bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080035 if result_code == -1:
36 raise Exception("zoops") # TODO
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050037 return _ffi.buffer(result_buffer)[:]
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080038
39
40
41def add(buffer, entropy):
42 """
43 Add data with a given entropy to the PRNG
44
45 :param buffer: Buffer with random data
46 :param entropy: The entropy (in bytes) measurement of the buffer
47 :return: None
48 """
49 if not isinstance(buffer, __builtin__.bytes):
50 raise TypeError("buffer must be a byte string")
51
52 if not isinstance(entropy, int):
53 raise TypeError("entropy must be an integer")
54
55 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050056 _lib.RAND_add(buffer, len(buffer), entropy)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080057
58
59
60def seed(buffer):
61 """
62 Alias for rand_add, with entropy equal to length
63
64 :param buffer: Buffer with random data
65 :return: None
66 """
67 if not isinstance(buffer, __builtin__.bytes):
68 raise TypeError("buffer must be a byte string")
69
70 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050071 _lib.RAND_seed(buffer, len(buffer))
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080072
73
74
75def status():
76 """
77 Retrieve the status of the PRNG
78
79 :return: True if the PRNG is seeded enough, false otherwise
80 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050081 return _lib.RAND_status()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080082
83
84
85def egd(path, bytes=_unspecified):
86 """
87 Query an entropy gathering daemon (EGD) for random data and add it to the
88 PRNG. I haven't found any problems when the socket is missing, the function
89 just returns 0.
90
91 :param path: The path to the EGD socket
92 :param bytes: (optional) The number of bytes to read, default is 255
93 :returns: The number of bytes read (NB: a value of 0 isn't necessarily an
94 error, check rand.status())
95 """
96 if not isinstance(path, str):
97 raise TypeError("path must be a string")
98
99 if bytes is _unspecified:
100 bytes = 255
101 elif not isinstance(bytes, int):
102 raise TypeError("bytes must be an integer")
103
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500104 return _lib.RAND_egd_bytes(path, bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800105
106
107
108def cleanup():
109 """
110 Erase the memory used by the PRNG.
111
112 :return: None
113 """
114 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500115 _lib.RAND_cleanup()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800116
117
118
119def load_file(filename, maxbytes=_unspecified):
120 """
121 Seed the PRNG with data from a file
122
123 :param filename: The file to read data from
124 :param maxbytes: (optional) The number of bytes to read, default is
125 to read the entire file
126 :return: The number of bytes read
127 """
128 if not isinstance(filename, str):
129 raise TypeError("filename must be a string")
130
131 if maxbytes is _unspecified:
132 maxbytes = -1
133 elif not isinstance(maxbytes, int):
134 raise TypeError("maxbytes must be an integer")
135
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 return _lib.RAND_load_file(filename, maxbytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800137
138
139
140def write_file(filename):
141 """
142 Save PRNG state to a file
143
144 :param filename: The file to write data to
145 :return: The number of bytes written
146 """
147 if not isinstance(filename, str):
148 raise TypeError("filename must be a string")
149
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 return _lib.RAND_write_file(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800151
152
153# TODO There are no tests for screen at all
154def screen():
155 """
156 Add the current contents of the screen to the PRNG state. Availability:
157 Windows.
158
159 :return: None
160 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500161 _lib.RAND_screen()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800162
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500163if getattr(_lib, 'RAND_screen', None) is None:
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800164 del screen
165
166
167# TODO There are no tests for the RAND strings being loaded, whatever that
168# means.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500169_lib.ERR_load_RAND_strings()