blob: 27d9f7edfd399f40f6bf2e1d0c2df9e2cc8b0e91 [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
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05007from functools import partial
Jean-Paul Calderone8210b922013-02-09 09:03:18 -08008
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05009from six import integer_types as _integer_types
10
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050011from OpenSSL._util import (
12 ffi as _ffi,
13 lib as _lib,
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -040014 exception_from_error_queue as _exception_from_error_queue,
15 path_string as _path_string)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050016
17
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080018class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050019 """
20 An error occurred in an `OpenSSL.rand` API.
21 """
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080022
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050023_raise_current_error = partial(_exception_from_error_queue, Error)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080024
25_unspecified = object()
26
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050027_builtin_bytes = bytes
28
Alex Gaynorca87ff62015-09-04 23:31:03 -040029
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080030def bytes(num_bytes):
31 """
32 Get some random bytes as a string.
33
34 :param num_bytes: The number of bytes to fetch
35 :return: A string of random bytes
36 """
Jean-Paul Calderone53a5e132014-01-11 08:31:19 -050037 if not isinstance(num_bytes, _integer_types):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080038 raise TypeError("num_bytes must be an integer")
39
40 if num_bytes < 0:
41 raise ValueError("num_bytes must not be negative")
42
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050043 result_buffer = _ffi.new("char[]", num_bytes)
44 result_code = _lib.RAND_bytes(result_buffer, num_bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080045 if result_code == -1:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050046 # TODO: No tests for this code path. Triggering a RAND_bytes failure
47 # might involve supplying a custom ENGINE? That's hard.
48 _raise_current_error()
49
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050050 return _ffi.buffer(result_buffer)[:]
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080051
52
53
54def add(buffer, entropy):
55 """
56 Add data with a given entropy to the PRNG
57
58 :param buffer: Buffer with random data
59 :param entropy: The entropy (in bytes) measurement of the buffer
60 :return: None
61 """
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050062 if not isinstance(buffer, _builtin_bytes):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080063 raise TypeError("buffer must be a byte string")
64
65 if not isinstance(entropy, int):
66 raise TypeError("entropy must be an integer")
67
68 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050069 _lib.RAND_add(buffer, len(buffer), entropy)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080070
71
72
73def seed(buffer):
74 """
75 Alias for rand_add, with entropy equal to length
76
77 :param buffer: Buffer with random data
78 :return: None
79 """
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050080 if not isinstance(buffer, _builtin_bytes):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080081 raise TypeError("buffer must be a byte string")
82
83 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050084 _lib.RAND_seed(buffer, len(buffer))
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080085
86
87
88def status():
89 """
90 Retrieve the status of the PRNG
91
92 :return: True if the PRNG is seeded enough, false otherwise
93 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050094 return _lib.RAND_status()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080095
96
97
98def egd(path, bytes=_unspecified):
99 """
100 Query an entropy gathering daemon (EGD) for random data and add it to the
101 PRNG. I haven't found any problems when the socket is missing, the function
102 just returns 0.
103
104 :param path: The path to the EGD socket
105 :param bytes: (optional) The number of bytes to read, default is 255
106 :returns: The number of bytes read (NB: a value of 0 isn't necessarily an
107 error, check rand.status())
108 """
Jean-Paul Calderonea8f7a942014-01-11 08:45:37 -0500109 if not isinstance(path, _builtin_bytes):
110 raise TypeError("path must be a byte string")
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800111
112 if bytes is _unspecified:
113 bytes = 255
114 elif not isinstance(bytes, int):
115 raise TypeError("bytes must be an integer")
116
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500117 return _lib.RAND_egd_bytes(path, bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800118
119
120
121def cleanup():
122 """
123 Erase the memory used by the PRNG.
124
125 :return: None
126 """
127 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500128 _lib.RAND_cleanup()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800129
130
131
132def load_file(filename, maxbytes=_unspecified):
133 """
134 Seed the PRNG with data from a file
135
Jean-Paul Calderone4e0c43f2015-04-13 10:15:17 -0400136 :param filename: The file to read data from (``bytes`` or ``unicode``).
137 :param maxbytes: (optional) The number of bytes to read, default is to read
138 the entire file
139
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800140 :return: The number of bytes read
141 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400142 filename = _path_string(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800143
144 if maxbytes is _unspecified:
145 maxbytes = -1
146 elif not isinstance(maxbytes, int):
147 raise TypeError("maxbytes must be an integer")
148
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500149 return _lib.RAND_load_file(filename, maxbytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800150
151
152
153def write_file(filename):
154 """
155 Save PRNG state to a file
156
Jean-Paul Calderone4e0c43f2015-04-13 10:15:17 -0400157 :param filename: The file to write data to (``bytes`` or ``unicode``).
158
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800159 :return: The number of bytes written
160 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400161 filename = _path_string(filename)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500162 return _lib.RAND_write_file(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800163
164
165# TODO There are no tests for screen at all
166def screen():
167 """
168 Add the current contents of the screen to the PRNG state. Availability:
169 Windows.
170
171 :return: None
172 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500173 _lib.RAND_screen()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800174
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500175if getattr(_lib, 'RAND_screen', None) is None:
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800176 del screen
177
178
179# TODO There are no tests for the RAND strings being loaded, whatever that
180# means.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500181_lib.ERR_load_RAND_strings()