blob: 7592fe049d5d9e5a871d96048cef5763ffb75d8f [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
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080029def bytes(num_bytes):
30 """
31 Get some random bytes as a string.
32
33 :param num_bytes: The number of bytes to fetch
34 :return: A string of random bytes
35 """
Jean-Paul Calderone53a5e132014-01-11 08:31:19 -050036 if not isinstance(num_bytes, _integer_types):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080037 raise TypeError("num_bytes must be an integer")
38
39 if num_bytes < 0:
40 raise ValueError("num_bytes must not be negative")
41
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050042 result_buffer = _ffi.new("char[]", num_bytes)
43 result_code = _lib.RAND_bytes(result_buffer, num_bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080044 if result_code == -1:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050045 # TODO: No tests for this code path. Triggering a RAND_bytes failure
46 # might involve supplying a custom ENGINE? That's hard.
47 _raise_current_error()
48
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050049 return _ffi.buffer(result_buffer)[:]
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080050
51
52
53def add(buffer, entropy):
54 """
55 Add data with a given entropy to the PRNG
56
57 :param buffer: Buffer with random data
58 :param entropy: The entropy (in bytes) measurement of the buffer
59 :return: None
60 """
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050061 if not isinstance(buffer, _builtin_bytes):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080062 raise TypeError("buffer must be a byte string")
63
64 if not isinstance(entropy, int):
65 raise TypeError("entropy must be an integer")
66
67 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050068 _lib.RAND_add(buffer, len(buffer), entropy)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080069
70
71
72def seed(buffer):
73 """
74 Alias for rand_add, with entropy equal to length
75
76 :param buffer: Buffer with random data
77 :return: None
78 """
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050079 if not isinstance(buffer, _builtin_bytes):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080080 raise TypeError("buffer must be a byte string")
81
82 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050083 _lib.RAND_seed(buffer, len(buffer))
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080084
85
86
87def status():
88 """
89 Retrieve the status of the PRNG
90
91 :return: True if the PRNG is seeded enough, false otherwise
92 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050093 return _lib.RAND_status()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080094
95
96
97def egd(path, bytes=_unspecified):
98 """
99 Query an entropy gathering daemon (EGD) for random data and add it to the
100 PRNG. I haven't found any problems when the socket is missing, the function
101 just returns 0.
102
103 :param path: The path to the EGD socket
104 :param bytes: (optional) The number of bytes to read, default is 255
105 :returns: The number of bytes read (NB: a value of 0 isn't necessarily an
106 error, check rand.status())
107 """
Jean-Paul Calderonea8f7a942014-01-11 08:45:37 -0500108 if not isinstance(path, _builtin_bytes):
109 raise TypeError("path must be a byte string")
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800110
111 if bytes is _unspecified:
112 bytes = 255
113 elif not isinstance(bytes, int):
114 raise TypeError("bytes must be an integer")
115
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500116 return _lib.RAND_egd_bytes(path, bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800117
118
119
120def cleanup():
121 """
122 Erase the memory used by the PRNG.
123
124 :return: None
125 """
126 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500127 _lib.RAND_cleanup()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800128
129
130
131def load_file(filename, maxbytes=_unspecified):
132 """
133 Seed the PRNG with data from a file
134
135 :param filename: The file to read data from
136 :param maxbytes: (optional) The number of bytes to read, default is
137 to read the entire file
138 :return: The number of bytes read
139 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400140 filename = _path_string(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800141
142 if maxbytes is _unspecified:
143 maxbytes = -1
144 elif not isinstance(maxbytes, int):
145 raise TypeError("maxbytes must be an integer")
146
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500147 return _lib.RAND_load_file(filename, maxbytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800148
149
150
151def write_file(filename):
152 """
153 Save PRNG state to a file
154
155 :param filename: The file to write data to
156 :return: The number of bytes written
157 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400158 filename = _path_string(filename)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500159 return _lib.RAND_write_file(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800160
161
162# TODO There are no tests for screen at all
163def screen():
164 """
165 Add the current contents of the screen to the PRNG state. Availability:
166 Windows.
167
168 :return: None
169 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500170 _lib.RAND_screen()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800171
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500172if getattr(_lib, 'RAND_screen', None) is None:
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800173 del screen
174
175
176# TODO There are no tests for the RAND strings being loaded, whatever that
177# means.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500178_lib.ERR_load_RAND_strings()