blob: 6f9f7110742df9827d5eff67f4d872e509e6b824 [file] [log] [blame]
Georg Brandl2daf6ae2012-02-20 19:54:16 +01001#include "Python.h"
2#ifdef MS_WINDOWS
Victor Stinner59f7fb22015-03-18 14:39:33 +01003# include <windows.h>
Martin Panterd2f87472016-07-29 04:00:44 +00004/* All sample MSDN wincrypt programs include the header below. It is at least
5 * required with Min GW. */
6# include <wincrypt.h>
Georg Brandl2daf6ae2012-02-20 19:54:16 +01007#else
Victor Stinner59f7fb22015-03-18 14:39:33 +01008# include <fcntl.h>
9# ifdef HAVE_SYS_STAT_H
10# include <sys/stat.h>
11# endif
Victor Stinnerdddf4842016-06-07 11:21:42 +020012# ifdef HAVE_LINUX_RANDOM_H
13# include <linux/random.h>
14# endif
Victor Stinnerbae2d622015-10-01 09:47:30 +020015# ifdef HAVE_GETRANDOM
16# include <sys/random.h>
17# elif defined(HAVE_GETRANDOM_SYSCALL)
Victor Stinner59f7fb22015-03-18 14:39:33 +010018# include <sys/syscall.h>
Victor Stinner59f7fb22015-03-18 14:39:33 +010019# endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +010020#endif
21
Benjamin Peterson69e97272012-02-21 11:08:50 -050022#ifdef Py_DEBUG
23int _Py_HashSecret_Initialized = 0;
24#else
25static int _Py_HashSecret_Initialized = 0;
26#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +010027
28#ifdef MS_WINDOWS
Georg Brandl2daf6ae2012-02-20 19:54:16 +010029static HCRYPTPROV hCryptProv = 0;
30
31static int
32win32_urandom_init(int raise)
33{
Georg Brandl2daf6ae2012-02-20 19:54:16 +010034 /* Acquire context */
Martin v. Löwis3f50bf62013-01-25 14:06:18 +010035 if (!CryptAcquireContext(&hCryptProv, NULL, NULL,
36 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010037 goto error;
38
39 return 0;
40
41error:
Victor Stinner4bad3b62016-08-16 15:23:58 +020042 if (raise) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +010043 PyErr_SetFromWindowsErr(0);
Victor Stinner4bad3b62016-08-16 15:23:58 +020044 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +010045 return -1;
46}
47
48/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
Victor Stinner4d6a3d62014-12-21 01:16:38 +010049 API. Return 0 on success, or raise an exception and return -1 on error. */
Georg Brandl2daf6ae2012-02-20 19:54:16 +010050static int
51win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
52{
53 Py_ssize_t chunk;
54
55 if (hCryptProv == 0)
56 {
Victor Stinner4bad3b62016-08-16 15:23:58 +020057 if (win32_urandom_init(raise) == -1) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +010058 return -1;
Victor Stinner4bad3b62016-08-16 15:23:58 +020059 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +010060 }
61
62 while (size > 0)
63 {
64 chunk = size > INT_MAX ? INT_MAX : size;
Victor Stinner0c083462013-11-15 23:26:25 +010065 if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010066 {
67 /* CryptGenRandom() failed */
Victor Stinner4bad3b62016-08-16 15:23:58 +020068 if (raise) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +010069 PyErr_SetFromWindowsErr(0);
Victor Stinner4bad3b62016-08-16 15:23:58 +020070 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +010071 return -1;
72 }
73 buffer += chunk;
74 size -= chunk;
75 }
76 return 0;
77}
Georg Brandl2daf6ae2012-02-20 19:54:16 +010078
Martin Panter39b10252016-06-10 08:07:11 +000079/* Issue #25003: Don't use getentropy() on Solaris (available since
Victor Stinnere66987e2016-09-06 16:33:52 -070080 * Solaris 11.3), it is blocking whereas os.urandom() should not block. */
Victor Stinnerbae2d622015-10-01 09:47:30 +020081#elif defined(HAVE_GETENTROPY) && !defined(sun)
82#define PY_GETENTROPY 1
83
Victor Stinner4d6a3d62014-12-21 01:16:38 +010084/* Fill buffer with size pseudo-random bytes generated by getentropy().
85 Return 0 on success, or raise an exception and return -1 on error.
Georg Brandl2daf6ae2012-02-20 19:54:16 +010086
Victor Stinner4bad3b62016-08-16 15:23:58 +020087 If raise is zero, don't raise an exception on error. */
Victor Stinner4d6a3d62014-12-21 01:16:38 +010088static int
Victor Stinner4bad3b62016-08-16 15:23:58 +020089py_getentropy(char *buffer, Py_ssize_t size, int raise)
Victor Stinner4d6a3d62014-12-21 01:16:38 +010090{
91 while (size > 0) {
92 Py_ssize_t len = Py_MIN(size, 256);
Victor Stinner9aa13312015-03-30 11:18:30 +020093 int res;
94
Victor Stinner4bad3b62016-08-16 15:23:58 +020095 if (raise) {
Victor Stinner9aa13312015-03-30 11:18:30 +020096 Py_BEGIN_ALLOW_THREADS
97 res = getentropy(buffer, len);
98 Py_END_ALLOW_THREADS
Victor Stinner4d6a3d62014-12-21 01:16:38 +010099 }
Victor Stinner9aa13312015-03-30 11:18:30 +0200100 else {
101 res = getentropy(buffer, len);
Victor Stinner4bad3b62016-08-16 15:23:58 +0200102 }
103
104 if (res < 0) {
105 if (raise) {
106 PyErr_SetFromErrno(PyExc_OSError);
107 }
108 return -1;
Victor Stinner9aa13312015-03-30 11:18:30 +0200109 }
110
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100111 buffer += len;
112 size -= len;
113 }
114 return 0;
115}
116
Victor Stinnerbae2d622015-10-01 09:47:30 +0200117#else
Victor Stinner59f7fb22015-03-18 14:39:33 +0100118
Victor Stinnerbae2d622015-10-01 09:47:30 +0200119#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
120#define PY_GETRANDOM 1
121
Victor Stinner6974cf22016-08-16 18:46:38 +0200122/* Call getrandom()
123 - Return 1 on success
Victor Stinner6d8bc462016-09-20 22:46:02 +0200124 - Return 0 if getrandom() syscall is not available (failed with ENOSYS or
125 EPERM) or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom
Victor Stinneraf597322016-09-20 22:26:18 +0200126 not initialized yet) and raise=0.
Victor Stinner6974cf22016-08-16 18:46:38 +0200127 - Raise an exception (if raise is non-zero) and return -1 on error:
128 getrandom() failed with EINTR and the Python signal handler raised an
129 exception, or getrandom() failed with a different error. */
Victor Stinner59f7fb22015-03-18 14:39:33 +0100130static int
Victor Stinnere66987e2016-09-06 16:33:52 -0700131py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
Victor Stinner59f7fb22015-03-18 14:39:33 +0100132{
Victor Stinnere66987e2016-09-06 16:33:52 -0700133 /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
Victor Stinner6d8bc462016-09-20 22:46:02 +0200134 failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris
Victor Stinneraf597322016-09-20 22:26:18 +0200135 11.3 or newer */
Victor Stinner59f7fb22015-03-18 14:39:33 +0100136 static int getrandom_works = 1;
Victor Stinnere66987e2016-09-06 16:33:52 -0700137 int flags;
Victor Stinnercfb19612016-06-08 10:16:50 +0200138 char *dest;
Victor Stinnerec721f32016-06-16 23:53:47 +0200139 long n;
Victor Stinner59f7fb22015-03-18 14:39:33 +0100140
Victor Stinner6974cf22016-08-16 18:46:38 +0200141 if (!getrandom_works) {
Victor Stinner59f7fb22015-03-18 14:39:33 +0100142 return 0;
Victor Stinner6974cf22016-08-16 18:46:38 +0200143 }
Victor Stinner59f7fb22015-03-18 14:39:33 +0100144
Victor Stinnere66987e2016-09-06 16:33:52 -0700145 flags = blocking ? 0 : GRND_NONBLOCK;
Victor Stinnercfb19612016-06-08 10:16:50 +0200146 dest = buffer;
Victor Stinner59f7fb22015-03-18 14:39:33 +0100147 while (0 < size) {
Victor Stinner9d242712016-04-12 22:28:49 +0200148#ifdef sun
149 /* Issue #26735: On Solaris, getrandom() is limited to returning up
150 to 1024 bytes */
151 n = Py_MIN(size, 1024);
152#else
Victor Stinnerec721f32016-06-16 23:53:47 +0200153 n = Py_MIN(size, LONG_MAX);
Victor Stinner9d242712016-04-12 22:28:49 +0200154#endif
Victor Stinner79b74ae2015-03-30 11:16:40 +0200155
Victor Stinner9d242712016-04-12 22:28:49 +0200156 errno = 0;
Victor Stinnerbae2d622015-10-01 09:47:30 +0200157#ifdef HAVE_GETRANDOM
158 if (raise) {
159 Py_BEGIN_ALLOW_THREADS
Victor Stinnercfb19612016-06-08 10:16:50 +0200160 n = getrandom(dest, n, flags);
Victor Stinnerbae2d622015-10-01 09:47:30 +0200161 Py_END_ALLOW_THREADS
162 }
163 else {
Victor Stinnercfb19612016-06-08 10:16:50 +0200164 n = getrandom(dest, n, flags);
Victor Stinnerbae2d622015-10-01 09:47:30 +0200165 }
166#else
167 /* On Linux, use the syscall() function because the GNU libc doesn't
Victor Stinner6974cf22016-08-16 18:46:38 +0200168 expose the Linux getrandom() syscall yet. See:
169 https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
Victor Stinner79b74ae2015-03-30 11:16:40 +0200170 if (raise) {
171 Py_BEGIN_ALLOW_THREADS
Victor Stinnercfb19612016-06-08 10:16:50 +0200172 n = syscall(SYS_getrandom, dest, n, flags);
Victor Stinner79b74ae2015-03-30 11:16:40 +0200173 Py_END_ALLOW_THREADS
174 }
175 else {
Victor Stinnercfb19612016-06-08 10:16:50 +0200176 n = syscall(SYS_getrandom, dest, n, flags);
Victor Stinner79b74ae2015-03-30 11:16:40 +0200177 }
Victor Stinnerbae2d622015-10-01 09:47:30 +0200178#endif
Victor Stinner79b74ae2015-03-30 11:16:40 +0200179
Victor Stinner59f7fb22015-03-18 14:39:33 +0100180 if (n < 0) {
Victor Stinneraf597322016-09-20 22:26:18 +0200181 /* ENOSYS: getrandom() syscall not supported by the kernel (but
Victor Stinner6d8bc462016-09-20 22:46:02 +0200182 * maybe supported by the host which built Python). EPERM:
183 * getrandom() syscall blocked by SECCOMP or something else. */
184 if (errno == ENOSYS || errno == EPERM) {
Victor Stinner59f7fb22015-03-18 14:39:33 +0100185 getrandom_works = 0;
186 return 0;
187 }
Victor Stinner6974cf22016-08-16 18:46:38 +0200188
Victor Stinnere66987e2016-09-06 16:33:52 -0700189 /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom
190 is not initialiazed yet. For _PyRandom_Init(), we ignore their
191 error and fall back on reading /dev/urandom which never blocks,
192 even if the system urandom is not initialized yet. */
193 if (errno == EAGAIN && !raise && !blocking) {
Victor Stinnerdddf4842016-06-07 11:21:42 +0200194 return 0;
195 }
Victor Stinner59f7fb22015-03-18 14:39:33 +0100196
197 if (errno == EINTR) {
Victor Stinnercecdd962016-08-16 15:19:09 +0200198 if (raise) {
199 if (PyErr_CheckSignals()) {
200 return -1;
201 }
Victor Stinner59f7fb22015-03-18 14:39:33 +0100202 }
Victor Stinnercecdd962016-08-16 15:19:09 +0200203
204 /* retry getrandom() if it was interrupted by a signal */
Victor Stinner59f7fb22015-03-18 14:39:33 +0100205 continue;
206 }
207
Victor Stinner4bad3b62016-08-16 15:23:58 +0200208 if (raise) {
Victor Stinner59f7fb22015-03-18 14:39:33 +0100209 PyErr_SetFromErrno(PyExc_OSError);
Victor Stinner4bad3b62016-08-16 15:23:58 +0200210 }
Victor Stinner59f7fb22015-03-18 14:39:33 +0100211 return -1;
212 }
213
Victor Stinnercfb19612016-06-08 10:16:50 +0200214 dest += n;
Victor Stinner59f7fb22015-03-18 14:39:33 +0100215 size -= n;
216 }
217 return 1;
218}
219#endif
220
Antoine Pitroue472aea2014-04-26 14:33:03 +0200221static struct {
222 int fd;
223 dev_t st_dev;
224 ino_t st_ino;
225} urandom_cache = { -1 };
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100226
Victor Stinner59f7fb22015-03-18 14:39:33 +0100227
Victor Stinnere66987e2016-09-06 16:33:52 -0700228/* Read 'size' random bytes from py_getrandom(). Fall back on reading from
Victor Stinner6974cf22016-08-16 18:46:38 +0200229 /dev/urandom if getrandom() is not available.
230
231 Return 0 on success. Raise an exception (if raise is non-zero) and return -1
232 on error. */
Victor Stinner4bad3b62016-08-16 15:23:58 +0200233static int
Victor Stinnere66987e2016-09-06 16:33:52 -0700234dev_urandom(char *buffer, Py_ssize_t size, int blocking, int raise)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100235{
236 int fd;
237 Py_ssize_t n;
Victor Stinnerbae2d622015-10-01 09:47:30 +0200238#ifdef PY_GETRANDOM
Victor Stinner59f7fb22015-03-18 14:39:33 +0100239 int res;
240#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100241
Victor Stinner6974cf22016-08-16 18:46:38 +0200242 assert(size > 0);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100243
Victor Stinnerbae2d622015-10-01 09:47:30 +0200244#ifdef PY_GETRANDOM
Victor Stinnere66987e2016-09-06 16:33:52 -0700245 res = py_getrandom(buffer, size, blocking, raise);
Victor Stinner6974cf22016-08-16 18:46:38 +0200246 if (res < 0) {
Victor Stinner59f7fb22015-03-18 14:39:33 +0100247 return -1;
Victor Stinner6974cf22016-08-16 18:46:38 +0200248 }
249 if (res == 1) {
Victor Stinner59f7fb22015-03-18 14:39:33 +0100250 return 0;
Victor Stinner6974cf22016-08-16 18:46:38 +0200251 }
Victor Stinner6d8bc462016-09-20 22:46:02 +0200252 /* getrandom() failed with ENOSYS or EPERM,
Victor Stinneraf597322016-09-20 22:26:18 +0200253 fall back on reading /dev/urandom */
Victor Stinner59f7fb22015-03-18 14:39:33 +0100254#endif
255
Victor Stinner6974cf22016-08-16 18:46:38 +0200256
257 if (raise) {
258 struct _Py_stat_struct st;
259
Antoine Pitroue472aea2014-04-26 14:33:03 +0200260 if (urandom_cache.fd >= 0) {
Victor Stinner6974cf22016-08-16 18:46:38 +0200261 /* Does the fd point to the same thing as before? (issue #21207) */
262 if (_Py_fstat_noraise(urandom_cache.fd, &st)
263 || st.st_dev != urandom_cache.st_dev
264 || st.st_ino != urandom_cache.st_ino) {
265 /* Something changed: forget the cached fd (but don't close it,
266 since it probably points to something important for some
267 third-party code). */
268 urandom_cache.fd = -1;
269 }
Antoine Pitrou4879a962013-08-31 00:26:02 +0200270 }
Victor Stinner6974cf22016-08-16 18:46:38 +0200271 if (urandom_cache.fd >= 0)
272 fd = urandom_cache.fd;
Antoine Pitroue472aea2014-04-26 14:33:03 +0200273 else {
Victor Stinner6974cf22016-08-16 18:46:38 +0200274 fd = _Py_open("/dev/urandom", O_RDONLY);
275 if (fd < 0) {
276 if (errno == ENOENT || errno == ENXIO ||
277 errno == ENODEV || errno == EACCES)
278 PyErr_SetString(PyExc_NotImplementedError,
279 "/dev/urandom (or equivalent) not found");
280 /* otherwise, keep the OSError exception raised by _Py_open() */
Antoine Pitroue472aea2014-04-26 14:33:03 +0200281 return -1;
282 }
Victor Stinner6974cf22016-08-16 18:46:38 +0200283 if (urandom_cache.fd >= 0) {
284 /* urandom_fd was initialized by another thread while we were
285 not holding the GIL, keep it. */
286 close(fd);
287 fd = urandom_cache.fd;
288 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200289 else {
Victor Stinner6974cf22016-08-16 18:46:38 +0200290 if (_Py_fstat(fd, &st)) {
291 close(fd);
292 return -1;
293 }
294 else {
295 urandom_cache.fd = fd;
296 urandom_cache.st_dev = st.st_dev;
297 urandom_cache.st_ino = st.st_ino;
298 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200299 }
300 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100301
Victor Stinner6974cf22016-08-16 18:46:38 +0200302 do {
303 n = _Py_read(fd, buffer, (size_t)size);
304 if (n == -1)
305 return -1;
306 if (n == 0) {
307 PyErr_Format(PyExc_RuntimeError,
308 "Failed to read %zi bytes from /dev/urandom",
309 size);
310 return -1;
311 }
312
313 buffer += n;
314 size -= n;
315 } while (0 < size);
316 }
317 else {
318 fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
319 if (fd < 0) {
Victor Stinnerc9382eb2015-03-19 23:36:33 +0100320 return -1;
321 }
322
Victor Stinner6974cf22016-08-16 18:46:38 +0200323 while (0 < size)
324 {
325 do {
326 n = read(fd, buffer, (size_t)size);
327 } while (n < 0 && errno == EINTR);
Victor Stinnerc9382eb2015-03-19 23:36:33 +0100328
Victor Stinner6974cf22016-08-16 18:46:38 +0200329 if (n <= 0) {
330 /* stop on error or if read(size) returned 0 */
Victor Stinner3ee933f2016-08-16 18:27:44 +0200331 close(fd);
Victor Stinner6974cf22016-08-16 18:46:38 +0200332 return -1;
333 }
334
335 buffer += n;
336 size -= n;
337 }
338 close(fd);
339 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100340 return 0;
341}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200342
343static void
344dev_urandom_close(void)
345{
Antoine Pitroue472aea2014-04-26 14:33:03 +0200346 if (urandom_cache.fd >= 0) {
347 close(urandom_cache.fd);
348 urandom_cache.fd = -1;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200349 }
350}
351
Victor Stinnerbae2d622015-10-01 09:47:30 +0200352#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100353
354/* Fill buffer with pseudo-random bytes generated by a linear congruent
355 generator (LCG):
356
357 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
358
359 Use bits 23..16 of x(n) to generate a byte. */
360static void
361lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
362{
363 size_t index;
364 unsigned int x;
365
366 x = x0;
367 for (index=0; index < size; index++) {
368 x *= 214013;
369 x += 2531011;
370 /* modulo 2 ^ (8 * sizeof(int)) */
371 buffer[index] = (x >> 16) & 0xff;
372 }
373}
374
Victor Stinner4bad3b62016-08-16 15:23:58 +0200375/* If raise is zero:
Victor Stinner6974cf22016-08-16 18:46:38 +0200376 - Don't raise exceptions on error
377 - Don't call PyErr_CheckSignals() on EINTR (retry directly the interrupted
378 syscall)
379 - Don't release the GIL to call syscalls. */
Victor Stinner4bad3b62016-08-16 15:23:58 +0200380static int
Victor Stinnere66987e2016-09-06 16:33:52 -0700381pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise)
Victor Stinner4bad3b62016-08-16 15:23:58 +0200382{
383 if (size < 0) {
384 if (raise) {
385 PyErr_Format(PyExc_ValueError,
386 "negative argument not allowed");
387 }
388 return -1;
389 }
390
391 if (size == 0) {
392 return 0;
393 }
394
395#ifdef MS_WINDOWS
396 return win32_urandom((unsigned char *)buffer, size, raise);
397#elif defined(PY_GETENTROPY)
398 return py_getentropy(buffer, size, raise);
399#else
Victor Stinnere66987e2016-09-06 16:33:52 -0700400 return dev_urandom(buffer, size, blocking, raise);
Victor Stinner4bad3b62016-08-16 15:23:58 +0200401#endif
402}
403
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200404/* Fill buffer with size pseudo-random bytes from the operating system random
Serhiy Storchaka56a6d852014-12-01 18:28:43 +0200405 number generator (RNG). It is suitable for most cryptographic purposes
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200406 except long living private keys for asymmetric encryption.
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100407
Victor Stinnere66987e2016-09-06 16:33:52 -0700408 On Linux 3.17 and newer, the getrandom() syscall is used in blocking mode:
409 block until the system urandom entropy pool is initialized (128 bits are
410 collected by the kernel).
411
412 Return 0 on success. Raise an exception and return -1 on error. */
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100413int
414_PyOS_URandom(void *buffer, Py_ssize_t size)
415{
Victor Stinnere66987e2016-09-06 16:33:52 -0700416 return pyurandom(buffer, size, 1, 1);
417}
418
419/* Fill buffer with size pseudo-random bytes from the operating system random
420 number generator (RNG). It is not suitable for cryptographic purpose.
421
422 On Linux 3.17 and newer (when getrandom() syscall is used), if the system
423 urandom is not initialized yet, the function returns "weak" entropy read
424 from /dev/urandom.
425
426 Return 0 on success. Raise an exception and return -1 on error. */
427int
428_PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
429{
430 return pyurandom(buffer, size, 0, 1);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100431}
432
433void
434_PyRandom_Init(void)
435{
436 char *env;
Christian Heimes985ecdc2013-11-20 11:46:18 +0100437 unsigned char *secret = (unsigned char *)&_Py_HashSecret.uc;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500438 Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
Serhiy Storchakafad85aa2015-11-07 15:42:38 +0200439 Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc));
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100440
Benjamin Peterson69e97272012-02-21 11:08:50 -0500441 if (_Py_HashSecret_Initialized)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100442 return;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500443 _Py_HashSecret_Initialized = 1;
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100444
445 /*
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100446 Hash randomization is enabled. Generate a per-process secret,
447 using PYTHONHASHSEED if provided.
448 */
449
450 env = Py_GETENV("PYTHONHASHSEED");
Georg Brandl12897d72012-02-20 23:49:29 +0100451 if (env && *env != '\0' && strcmp(env, "random") != 0) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100452 char *endptr = env;
453 unsigned long seed;
454 seed = strtoul(env, &endptr, 10);
455 if (*endptr != '\0'
456 || seed > 4294967295UL
457 || (errno == ERANGE && seed == ULONG_MAX))
458 {
459 Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
460 "in range [0; 4294967295]");
461 }
462 if (seed == 0) {
463 /* disable the randomized hash */
464 memset(secret, 0, secret_size);
465 }
466 else {
Christian Heimes985ecdc2013-11-20 11:46:18 +0100467 lcg_urandom(seed, secret, secret_size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100468 }
469 }
470 else {
Victor Stinner4bad3b62016-08-16 15:23:58 +0200471 int res;
472
473 /* _PyRandom_Init() is called very early in the Python initialization
Victor Stinnere66987e2016-09-06 16:33:52 -0700474 and so exceptions cannot be used (use raise=0).
475
476 _PyRandom_Init() must not block Python initialization: call
477 pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
478 res = pyurandom(secret, secret_size, 0, 0);
Victor Stinner4bad3b62016-08-16 15:23:58 +0200479 if (res < 0) {
480 Py_FatalError("failed to get random numbers to initialize Python");
481 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100482 }
483}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200484
485void
486_PyRandom_Fini(void)
487{
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200488#ifdef MS_WINDOWS
489 if (hCryptProv) {
Tim Goldenb8ac3e12014-05-06 13:29:45 +0100490 CryptReleaseContext(hCryptProv, 0);
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200491 hCryptProv = 0;
492 }
Victor Stinnerbae2d622015-10-01 09:47:30 +0200493#elif defined(PY_GETENTROPY)
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100494 /* nothing to clean */
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200495#else
Antoine Pitrou4879a962013-08-31 00:26:02 +0200496 dev_urandom_close();
497#endif
498}