blob: af3d0bd0d57eff17819929e54de4fdc26a953137 [file] [log] [blame]
Georg Brandl2daf6ae2012-02-20 19:54:16 +01001#include "Python.h"
2#ifdef MS_WINDOWS
3#include <windows.h>
4#else
5#include <fcntl.h>
Antoine Pitroue472aea2014-04-26 14:33:03 +02006#ifdef HAVE_SYS_STAT_H
7#include <sys/stat.h>
8#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +01009#endif
10
Benjamin Peterson69e97272012-02-21 11:08:50 -050011#ifdef Py_DEBUG
12int _Py_HashSecret_Initialized = 0;
13#else
14static int _Py_HashSecret_Initialized = 0;
15#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +010016
17#ifdef MS_WINDOWS
Georg Brandl2daf6ae2012-02-20 19:54:16 +010018static HCRYPTPROV hCryptProv = 0;
19
20static int
21win32_urandom_init(int raise)
22{
Georg Brandl2daf6ae2012-02-20 19:54:16 +010023 /* Acquire context */
Martin v. Löwis3f50bf62013-01-25 14:06:18 +010024 if (!CryptAcquireContext(&hCryptProv, NULL, NULL,
25 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010026 goto error;
27
28 return 0;
29
30error:
31 if (raise)
32 PyErr_SetFromWindowsErr(0);
33 else
34 Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
35 return -1;
36}
37
38/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
Victor Stinnerfe02e392014-12-21 01:16:38 +010039 API. Return 0 on success, or raise an exception and return -1 on error. */
Georg Brandl2daf6ae2012-02-20 19:54:16 +010040static int
41win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
42{
43 Py_ssize_t chunk;
44
45 if (hCryptProv == 0)
46 {
47 if (win32_urandom_init(raise) == -1)
48 return -1;
49 }
50
51 while (size > 0)
52 {
53 chunk = size > INT_MAX ? INT_MAX : size;
Victor Stinner0c083462013-11-15 23:26:25 +010054 if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010055 {
56 /* CryptGenRandom() failed */
57 if (raise)
58 PyErr_SetFromWindowsErr(0);
59 else
60 Py_FatalError("Failed to initialized the randomized hash "
61 "secret using CryptoGen)");
62 return -1;
63 }
64 buffer += chunk;
65 size -= chunk;
66 }
67 return 0;
68}
Georg Brandl2daf6ae2012-02-20 19:54:16 +010069
Victor Stinner78cc2e82015-10-01 09:59:32 +020070/* Issue #25003: Don' use getentropy() on Solaris (available since
71 * Solaris 11.3), it is blocking whereas os.urandom() should not block. */
72#elif defined(HAVE_GETENTROPY) && !defined(sun)
73#define PY_GETENTROPY 1
74
Victor Stinnerfe02e392014-12-21 01:16:38 +010075/* Fill buffer with size pseudo-random bytes generated by getentropy().
76 Return 0 on success, or raise an exception and return -1 on error.
Georg Brandl2daf6ae2012-02-20 19:54:16 +010077
Victor Stinnerfe02e392014-12-21 01:16:38 +010078 If fatal is nonzero, call Py_FatalError() instead of raising an exception
79 on error. */
80static int
81py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
82{
83 while (size > 0) {
84 Py_ssize_t len = Py_MIN(size, 256);
Victor Stinner9aa13312015-03-30 11:18:30 +020085 int res;
86
87 if (!fatal) {
88 Py_BEGIN_ALLOW_THREADS
89 res = getentropy(buffer, len);
90 Py_END_ALLOW_THREADS
91
92 if (res < 0) {
Victor Stinnerfe02e392014-12-21 01:16:38 +010093 PyErr_SetFromErrno(PyExc_OSError);
94 return -1;
95 }
96 }
Victor Stinner9aa13312015-03-30 11:18:30 +020097 else {
98 res = getentropy(buffer, len);
99 if (res < 0)
100 Py_FatalError("getentropy() failed");
101 }
102
Victor Stinnerfe02e392014-12-21 01:16:38 +0100103 buffer += len;
104 size -= len;
105 }
106 return 0;
107}
108
109#else
Antoine Pitroue472aea2014-04-26 14:33:03 +0200110static struct {
111 int fd;
112 dev_t st_dev;
113 ino_t st_ino;
114} urandom_cache = { -1 };
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100115
116/* Read size bytes from /dev/urandom into buffer.
117 Call Py_FatalError() on error. */
118static void
Christian Heimes985ecdc2013-11-20 11:46:18 +0100119dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100120{
121 int fd;
122 Py_ssize_t n;
123
124 assert (0 < size);
125
Victor Stinnerdaf45552013-08-28 00:53:59 +0200126 fd = _Py_open("/dev/urandom", O_RDONLY);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100127 if (fd < 0)
128 Py_FatalError("Failed to open /dev/urandom");
129
130 while (0 < size)
131 {
132 do {
133 n = read(fd, buffer, (size_t)size);
134 } while (n < 0 && errno == EINTR);
135 if (n <= 0)
136 {
137 /* stop on error or if read(size) returned 0 */
138 Py_FatalError("Failed to read bytes from /dev/urandom");
139 break;
140 }
141 buffer += n;
142 size -= (Py_ssize_t)n;
143 }
144 close(fd);
145}
146
147/* Read size bytes from /dev/urandom into buffer.
148 Return 0 on success, raise an exception and return -1 on error. */
149static int
150dev_urandom_python(char *buffer, Py_ssize_t size)
151{
152 int fd;
153 Py_ssize_t n;
Antoine Pitroue472aea2014-04-26 14:33:03 +0200154 struct stat st;
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100155
156 if (size <= 0)
157 return 0;
158
Antoine Pitroue472aea2014-04-26 14:33:03 +0200159 if (urandom_cache.fd >= 0) {
160 /* Does the fd point to the same thing as before? (issue #21207) */
161 if (fstat(urandom_cache.fd, &st)
162 || st.st_dev != urandom_cache.st_dev
163 || st.st_ino != urandom_cache.st_ino) {
164 /* Something changed: forget the cached fd (but don't close it,
165 since it probably points to something important for some
166 third-party code). */
167 urandom_cache.fd = -1;
168 }
169 }
170 if (urandom_cache.fd >= 0)
171 fd = urandom_cache.fd;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200172 else {
173 Py_BEGIN_ALLOW_THREADS
174 fd = _Py_open("/dev/urandom", O_RDONLY);
175 Py_END_ALLOW_THREADS
176 if (fd < 0)
177 {
178 if (errno == ENOENT || errno == ENXIO ||
179 errno == ENODEV || errno == EACCES)
180 PyErr_SetString(PyExc_NotImplementedError,
181 "/dev/urandom (or equivalent) not found");
182 else
183 PyErr_SetFromErrno(PyExc_OSError);
184 return -1;
185 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200186 if (urandom_cache.fd >= 0) {
Antoine Pitrou4879a962013-08-31 00:26:02 +0200187 /* urandom_fd was initialized by another thread while we were
188 not holding the GIL, keep it. */
189 close(fd);
Antoine Pitroue472aea2014-04-26 14:33:03 +0200190 fd = urandom_cache.fd;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200191 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200192 else {
193 if (fstat(fd, &st)) {
194 PyErr_SetFromErrno(PyExc_OSError);
195 close(fd);
196 return -1;
197 }
198 else {
199 urandom_cache.fd = fd;
200 urandom_cache.st_dev = st.st_dev;
201 urandom_cache.st_ino = st.st_ino;
202 }
203 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100204 }
205
206 Py_BEGIN_ALLOW_THREADS
207 do {
208 do {
209 n = read(fd, buffer, (size_t)size);
210 } while (n < 0 && errno == EINTR);
211 if (n <= 0)
212 break;
213 buffer += n;
214 size -= (Py_ssize_t)n;
215 } while (0 < size);
216 Py_END_ALLOW_THREADS
217
218 if (n <= 0)
219 {
220 /* stop on error or if read(size) returned 0 */
221 if (n < 0)
222 PyErr_SetFromErrno(PyExc_OSError);
223 else
224 PyErr_Format(PyExc_RuntimeError,
225 "Failed to read %zi bytes from /dev/urandom",
226 size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100227 return -1;
228 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100229 return 0;
230}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200231
232static void
233dev_urandom_close(void)
234{
Antoine Pitroue472aea2014-04-26 14:33:03 +0200235 if (urandom_cache.fd >= 0) {
236 close(urandom_cache.fd);
237 urandom_cache.fd = -1;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200238 }
239}
240
Victor Stinnerfe02e392014-12-21 01:16:38 +0100241#endif /* HAVE_GETENTROPY */
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100242
243/* Fill buffer with pseudo-random bytes generated by a linear congruent
244 generator (LCG):
245
246 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
247
248 Use bits 23..16 of x(n) to generate a byte. */
249static void
250lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
251{
252 size_t index;
253 unsigned int x;
254
255 x = x0;
256 for (index=0; index < size; index++) {
257 x *= 214013;
258 x += 2531011;
259 /* modulo 2 ^ (8 * sizeof(int)) */
260 buffer[index] = (x >> 16) & 0xff;
261 }
262}
263
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200264/* Fill buffer with size pseudo-random bytes from the operating system random
Serhiy Storchaka56a6d852014-12-01 18:28:43 +0200265 number generator (RNG). It is suitable for most cryptographic purposes
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200266 except long living private keys for asymmetric encryption.
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100267
268 Return 0 on success, raise an exception and return -1 on error. */
269int
270_PyOS_URandom(void *buffer, Py_ssize_t size)
271{
272 if (size < 0) {
273 PyErr_Format(PyExc_ValueError,
274 "negative argument not allowed");
275 return -1;
276 }
277 if (size == 0)
278 return 0;
279
280#ifdef MS_WINDOWS
281 return win32_urandom((unsigned char *)buffer, size, 1);
Victor Stinner78cc2e82015-10-01 09:59:32 +0200282#elif defined(PY_GETENTROPY)
Victor Stinnerfe02e392014-12-21 01:16:38 +0100283 return py_getentropy(buffer, size, 0);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100284#else
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100285 return dev_urandom_python((char*)buffer, size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100286#endif
287}
288
289void
290_PyRandom_Init(void)
291{
292 char *env;
Christian Heimes985ecdc2013-11-20 11:46:18 +0100293 unsigned char *secret = (unsigned char *)&_Py_HashSecret.uc;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500294 Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
Christian Heimes985ecdc2013-11-20 11:46:18 +0100295 assert(secret_size == sizeof(_Py_HashSecret.uc));
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100296
Benjamin Peterson69e97272012-02-21 11:08:50 -0500297 if (_Py_HashSecret_Initialized)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100298 return;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500299 _Py_HashSecret_Initialized = 1;
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100300
301 /*
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100302 Hash randomization is enabled. Generate a per-process secret,
303 using PYTHONHASHSEED if provided.
304 */
305
306 env = Py_GETENV("PYTHONHASHSEED");
Georg Brandl12897d72012-02-20 23:49:29 +0100307 if (env && *env != '\0' && strcmp(env, "random") != 0) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100308 char *endptr = env;
309 unsigned long seed;
310 seed = strtoul(env, &endptr, 10);
311 if (*endptr != '\0'
312 || seed > 4294967295UL
313 || (errno == ERANGE && seed == ULONG_MAX))
314 {
315 Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
316 "in range [0; 4294967295]");
317 }
318 if (seed == 0) {
319 /* disable the randomized hash */
320 memset(secret, 0, secret_size);
321 }
322 else {
Christian Heimes985ecdc2013-11-20 11:46:18 +0100323 lcg_urandom(seed, secret, secret_size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100324 }
325 }
326 else {
327#ifdef MS_WINDOWS
Christian Heimes985ecdc2013-11-20 11:46:18 +0100328 (void)win32_urandom(secret, secret_size, 0);
Victor Stinner78cc2e82015-10-01 09:59:32 +0200329#elif defined(PY_GETENTROPY)
Victor Stinnerfe02e392014-12-21 01:16:38 +0100330 (void)py_getentropy(secret, secret_size, 1);
Christian Heimesaf01f662013-12-21 16:19:10 +0100331#else
Christian Heimes985ecdc2013-11-20 11:46:18 +0100332 dev_urandom_noraise(secret, secret_size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100333#endif
334 }
335}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200336
337void
338_PyRandom_Fini(void)
339{
Victor Stinnerfe02e392014-12-21 01:16:38 +0100340#ifdef MS_WINDOWS
341 if (hCryptProv) {
342 CryptReleaseContext(hCryptProv, 0);
343 hCryptProv = 0;
344 }
Victor Stinner78cc2e82015-10-01 09:59:32 +0200345#elif defined(PY_GETENTROPY)
Victor Stinnerfe02e392014-12-21 01:16:38 +0100346 /* nothing to clean */
347#else
Antoine Pitrou4879a962013-08-31 00:26:02 +0200348 dev_urandom_close();
349#endif
350}