blob: 65cd597153fab3dce557eb95169ef2cd2ef99726 [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
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080053def 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
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080071def seed(buffer):
72 """
73 Alias for rand_add, with entropy equal to length
74
75 :param buffer: Buffer with random data
76 :return: None
77 """
Jean-Paul Calderonee80a25a2014-01-09 14:33:42 -050078 if not isinstance(buffer, _builtin_bytes):
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080079 raise TypeError("buffer must be a byte string")
80
81 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050082 _lib.RAND_seed(buffer, len(buffer))
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080083
84
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080085def status():
86 """
87 Retrieve the status of the PRNG
88
89 :return: True if the PRNG is seeded enough, false otherwise
90 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050091 return _lib.RAND_status()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080092
93
Jean-Paul Calderone8210b922013-02-09 09:03:18 -080094def egd(path, bytes=_unspecified):
95 """
96 Query an entropy gathering daemon (EGD) for random data and add it to the
97 PRNG. I haven't found any problems when the socket is missing, the function
98 just returns 0.
99
100 :param path: The path to the EGD socket
101 :param bytes: (optional) The number of bytes to read, default is 255
102 :returns: The number of bytes read (NB: a value of 0 isn't necessarily an
103 error, check rand.status())
104 """
Jean-Paul Calderonea8f7a942014-01-11 08:45:37 -0500105 if not isinstance(path, _builtin_bytes):
106 raise TypeError("path must be a byte string")
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800107
108 if bytes is _unspecified:
109 bytes = 255
110 elif not isinstance(bytes, int):
111 raise TypeError("bytes must be an integer")
112
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500113 return _lib.RAND_egd_bytes(path, bytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800114
115
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800116def cleanup():
117 """
118 Erase the memory used by the PRNG.
119
120 :return: None
121 """
122 # TODO Nothing tests this call actually being made, or made properly.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500123 _lib.RAND_cleanup()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800124
125
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800126def load_file(filename, maxbytes=_unspecified):
127 """
128 Seed the PRNG with data from a file
129
Jean-Paul Calderone4e0c43f2015-04-13 10:15:17 -0400130 :param filename: The file to read data from (``bytes`` or ``unicode``).
131 :param maxbytes: (optional) The number of bytes to read, default is to read
132 the entire file
133
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800134 :return: The number of bytes read
135 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400136 filename = _path_string(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800137
138 if maxbytes is _unspecified:
139 maxbytes = -1
140 elif not isinstance(maxbytes, int):
141 raise TypeError("maxbytes must be an integer")
142
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500143 return _lib.RAND_load_file(filename, maxbytes)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800144
145
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800146def write_file(filename):
147 """
148 Save PRNG state to a file
149
Jean-Paul Calderone4e0c43f2015-04-13 10:15:17 -0400150 :param filename: The file to write data to (``bytes`` or ``unicode``).
151
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800152 :return: The number of bytes written
153 """
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -0400154 filename = _path_string(filename)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500155 return _lib.RAND_write_file(filename)
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800156
157
158# TODO There are no tests for screen at all
159def screen():
160 """
161 Add the current contents of the screen to the PRNG state. Availability:
162 Windows.
163
164 :return: None
165 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 _lib.RAND_screen()
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800167
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500168if getattr(_lib, 'RAND_screen', None) is None:
Jean-Paul Calderone8210b922013-02-09 09:03:18 -0800169 del screen
170
171
172# TODO There are no tests for the RAND strings being loaded, whatever that
173# means.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500174_lib.ERR_load_RAND_strings()