blob: a281829f9744ee8143b8173fb5e7a12a0a12b113 [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>
Georg Brandl2daf6ae2012-02-20 19:54:16 +01004#else
Victor Stinner59f7fb22015-03-18 14:39:33 +01005# include <fcntl.h>
6# ifdef HAVE_SYS_STAT_H
7# include <sys/stat.h>
8# endif
Victor Stinner9eb57c52015-03-19 22:21:49 +01009# ifdef HAVE_GETRANDOM_SYSCALL
Victor Stinner59f7fb22015-03-18 14:39:33 +010010# include <sys/syscall.h>
Victor Stinner59f7fb22015-03-18 14:39:33 +010011# endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +010012#endif
13
Benjamin Peterson69e97272012-02-21 11:08:50 -050014#ifdef Py_DEBUG
15int _Py_HashSecret_Initialized = 0;
16#else
17static int _Py_HashSecret_Initialized = 0;
18#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +010019
20#ifdef MS_WINDOWS
Georg Brandl2daf6ae2012-02-20 19:54:16 +010021static HCRYPTPROV hCryptProv = 0;
22
23static int
24win32_urandom_init(int raise)
25{
Georg Brandl2daf6ae2012-02-20 19:54:16 +010026 /* Acquire context */
Martin v. Löwis3f50bf62013-01-25 14:06:18 +010027 if (!CryptAcquireContext(&hCryptProv, NULL, NULL,
28 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010029 goto error;
30
31 return 0;
32
33error:
34 if (raise)
35 PyErr_SetFromWindowsErr(0);
36 else
37 Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
38 return -1;
39}
40
41/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
Victor Stinner4d6a3d62014-12-21 01:16:38 +010042 API. Return 0 on success, or raise an exception and return -1 on error. */
Georg Brandl2daf6ae2012-02-20 19:54:16 +010043static int
44win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
45{
46 Py_ssize_t chunk;
47
48 if (hCryptProv == 0)
49 {
50 if (win32_urandom_init(raise) == -1)
51 return -1;
52 }
53
54 while (size > 0)
55 {
56 chunk = size > INT_MAX ? INT_MAX : size;
Victor Stinner0c083462013-11-15 23:26:25 +010057 if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
Georg Brandl2daf6ae2012-02-20 19:54:16 +010058 {
59 /* CryptGenRandom() failed */
60 if (raise)
61 PyErr_SetFromWindowsErr(0);
62 else
63 Py_FatalError("Failed to initialized the randomized hash "
64 "secret using CryptoGen)");
65 return -1;
66 }
67 buffer += chunk;
68 size -= chunk;
69 }
70 return 0;
71}
Georg Brandl2daf6ae2012-02-20 19:54:16 +010072
Victor Stinner4d6a3d62014-12-21 01:16:38 +010073#elif HAVE_GETENTROPY
74/* Fill buffer with size pseudo-random bytes generated by getentropy().
75 Return 0 on success, or raise an exception and return -1 on error.
Georg Brandl2daf6ae2012-02-20 19:54:16 +010076
Victor Stinner4d6a3d62014-12-21 01:16:38 +010077 If fatal is nonzero, call Py_FatalError() instead of raising an exception
78 on error. */
79static int
80py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
81{
82 while (size > 0) {
83 Py_ssize_t len = Py_MIN(size, 256);
84 int res = getentropy(buffer, len);
85 if (res < 0) {
86 if (fatal) {
87 Py_FatalError("getentropy() failed");
88 }
89 else {
90 PyErr_SetFromErrno(PyExc_OSError);
91 return -1;
92 }
93 }
94 buffer += len;
95 size -= len;
96 }
97 return 0;
98}
99
Victor Stinner59f7fb22015-03-18 14:39:33 +0100100#else /* !HAVE_GETENTROPY */
101
Victor Stinner9eb57c52015-03-19 22:21:49 +0100102#ifdef HAVE_GETRANDOM_SYSCALL
Victor Stinner59f7fb22015-03-18 14:39:33 +0100103static int
104py_getrandom(void *buffer, Py_ssize_t size, int raise)
105{
106 /* is getrandom() supported by the running kernel?
107 * need Linux kernel 3.17 or later */
108 static int getrandom_works = 1;
109 /* Use /dev/urandom, block if the kernel has no entropy */
110 const int flags = 0;
111 int n;
112
113 if (!getrandom_works)
114 return 0;
115
116 while (0 < size) {
117 errno = 0;
118 /* the libc doesn't expose getrandom() yet, see:
119 * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
120 n = syscall(SYS_getrandom, buffer, size, flags);
121 if (n < 0) {
122 if (errno == ENOSYS) {
123 getrandom_works = 0;
124 return 0;
125 }
126
127 if (errno == EINTR) {
128 /* Note: EINTR should not occur with flags=0 */
129 if (PyErr_CheckSignals()) {
130 if (!raise)
131 Py_FatalError("getrandom() interrupted by a signal");
132 return -1;
133 }
134 /* retry getrandom() */
135 continue;
136 }
137
138 if (raise)
139 PyErr_SetFromErrno(PyExc_OSError);
140 else
141 Py_FatalError("getrandom() failed");
142 return -1;
143 }
144
145 buffer += n;
146 size -= n;
147 }
148 return 1;
149}
150#endif
151
Antoine Pitroue472aea2014-04-26 14:33:03 +0200152static struct {
153 int fd;
154 dev_t st_dev;
155 ino_t st_ino;
156} urandom_cache = { -1 };
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100157
Victor Stinner59f7fb22015-03-18 14:39:33 +0100158
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100159/* Read size bytes from /dev/urandom into buffer.
160 Call Py_FatalError() on error. */
161static void
Christian Heimes985ecdc2013-11-20 11:46:18 +0100162dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100163{
164 int fd;
165 Py_ssize_t n;
166
167 assert (0 < size);
168
Victor Stinner9eb57c52015-03-19 22:21:49 +0100169#ifdef HAVE_GETRANDOM_SYSCALL
Victor Stinner59f7fb22015-03-18 14:39:33 +0100170 if (py_getrandom(buffer, size, 0) == 1)
171 return;
172 /* getrandom() is not supported by the running kernel, fall back
173 * on reading /dev/urandom */
174#endif
175
Victor Stinnerc7cd12d2015-03-19 23:24:45 +0100176 fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
177 if (fd < 0)
178 Py_FatalError("Failed to open /dev/urandom");
179
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100180 while (0 < size)
181 {
182 do {
183 n = read(fd, buffer, (size_t)size);
184 } while (n < 0 && errno == EINTR);
185 if (n <= 0)
186 {
187 /* stop on error or if read(size) returned 0 */
188 Py_FatalError("Failed to read bytes from /dev/urandom");
189 break;
190 }
191 buffer += n;
192 size -= (Py_ssize_t)n;
193 }
194 close(fd);
195}
196
197/* Read size bytes from /dev/urandom into buffer.
198 Return 0 on success, raise an exception and return -1 on error. */
199static int
200dev_urandom_python(char *buffer, Py_ssize_t size)
201{
202 int fd;
203 Py_ssize_t n;
Steve Dowerf2f373f2015-02-21 08:44:05 -0800204 struct _Py_stat_struct st;
Victor Stinner9eb57c52015-03-19 22:21:49 +0100205#ifdef HAVE_GETRANDOM_SYSCALL
Victor Stinner59f7fb22015-03-18 14:39:33 +0100206 int res;
207#endif
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100208
209 if (size <= 0)
210 return 0;
211
Victor Stinner9eb57c52015-03-19 22:21:49 +0100212#ifdef HAVE_GETRANDOM_SYSCALL
Victor Stinner59f7fb22015-03-18 14:39:33 +0100213 res = py_getrandom(buffer, size, 1);
214 if (res < 0)
215 return -1;
216 if (res == 1)
217 return 0;
218 /* getrandom() is not supported by the running kernel, fall back
219 * on reading /dev/urandom */
220#endif
221
Antoine Pitroue472aea2014-04-26 14:33:03 +0200222 if (urandom_cache.fd >= 0) {
223 /* Does the fd point to the same thing as before? (issue #21207) */
Steve Dowerf2f373f2015-02-21 08:44:05 -0800224 if (_Py_fstat(urandom_cache.fd, &st)
Antoine Pitroue472aea2014-04-26 14:33:03 +0200225 || st.st_dev != urandom_cache.st_dev
226 || st.st_ino != urandom_cache.st_ino) {
227 /* Something changed: forget the cached fd (but don't close it,
228 since it probably points to something important for some
229 third-party code). */
230 urandom_cache.fd = -1;
231 }
232 }
233 if (urandom_cache.fd >= 0)
234 fd = urandom_cache.fd;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200235 else {
Antoine Pitrou4879a962013-08-31 00:26:02 +0200236 fd = _Py_open("/dev/urandom", O_RDONLY);
Victor Stinnera555cfc2015-03-18 00:22:14 +0100237 if (fd < 0) {
Antoine Pitrou4879a962013-08-31 00:26:02 +0200238 if (errno == ENOENT || errno == ENXIO ||
239 errno == ENODEV || errno == EACCES)
240 PyErr_SetString(PyExc_NotImplementedError,
241 "/dev/urandom (or equivalent) not found");
Victor Stinnera555cfc2015-03-18 00:22:14 +0100242 /* otherwise, keep the OSError exception raised by _Py_open() */
Antoine Pitrou4879a962013-08-31 00:26:02 +0200243 return -1;
244 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200245 if (urandom_cache.fd >= 0) {
Antoine Pitrou4879a962013-08-31 00:26:02 +0200246 /* urandom_fd was initialized by another thread while we were
247 not holding the GIL, keep it. */
248 close(fd);
Antoine Pitroue472aea2014-04-26 14:33:03 +0200249 fd = urandom_cache.fd;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200250 }
Antoine Pitroue472aea2014-04-26 14:33:03 +0200251 else {
Steve Dowerf2f373f2015-02-21 08:44:05 -0800252 if (_Py_fstat(fd, &st)) {
Antoine Pitroue472aea2014-04-26 14:33:03 +0200253 PyErr_SetFromErrno(PyExc_OSError);
254 close(fd);
255 return -1;
256 }
257 else {
258 urandom_cache.fd = fd;
259 urandom_cache.st_dev = st.st_dev;
260 urandom_cache.st_ino = st.st_ino;
261 }
262 }
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100263 }
264
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100265 do {
Victor Stinnerc9382eb2015-03-19 23:36:33 +0100266 n = _Py_read(fd, buffer, (size_t)size);
267 if (n == -1)
268 return -1;
269 if (n == 0) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100270 PyErr_Format(PyExc_RuntimeError,
Victor Stinnerc9382eb2015-03-19 23:36:33 +0100271 "Failed to read %zi bytes from /dev/urandom",
272 size);
273 return -1;
274 }
275
276 buffer += n;
277 size -= n;
278 } while (0 < size);
279
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100280 return 0;
281}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200282
283static void
284dev_urandom_close(void)
285{
Antoine Pitroue472aea2014-04-26 14:33:03 +0200286 if (urandom_cache.fd >= 0) {
287 close(urandom_cache.fd);
288 urandom_cache.fd = -1;
Antoine Pitrou4879a962013-08-31 00:26:02 +0200289 }
290}
291
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100292#endif /* HAVE_GETENTROPY */
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100293
294/* Fill buffer with pseudo-random bytes generated by a linear congruent
295 generator (LCG):
296
297 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
298
299 Use bits 23..16 of x(n) to generate a byte. */
300static void
301lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
302{
303 size_t index;
304 unsigned int x;
305
306 x = x0;
307 for (index=0; index < size; index++) {
308 x *= 214013;
309 x += 2531011;
310 /* modulo 2 ^ (8 * sizeof(int)) */
311 buffer[index] = (x >> 16) & 0xff;
312 }
313}
314
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200315/* Fill buffer with size pseudo-random bytes from the operating system random
Serhiy Storchaka56a6d852014-12-01 18:28:43 +0200316 number generator (RNG). It is suitable for most cryptographic purposes
Georg Brandlc6a2c9b2013-10-06 18:43:19 +0200317 except long living private keys for asymmetric encryption.
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100318
319 Return 0 on success, raise an exception and return -1 on error. */
320int
321_PyOS_URandom(void *buffer, Py_ssize_t size)
322{
323 if (size < 0) {
324 PyErr_Format(PyExc_ValueError,
325 "negative argument not allowed");
326 return -1;
327 }
328 if (size == 0)
329 return 0;
330
331#ifdef MS_WINDOWS
332 return win32_urandom((unsigned char *)buffer, size, 1);
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100333#elif HAVE_GETENTROPY
334 return py_getentropy(buffer, size, 0);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100335#else
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100336 return dev_urandom_python((char*)buffer, size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100337#endif
338}
339
340void
341_PyRandom_Init(void)
342{
343 char *env;
Christian Heimes985ecdc2013-11-20 11:46:18 +0100344 unsigned char *secret = (unsigned char *)&_Py_HashSecret.uc;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500345 Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
Christian Heimes985ecdc2013-11-20 11:46:18 +0100346 assert(secret_size == sizeof(_Py_HashSecret.uc));
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100347
Benjamin Peterson69e97272012-02-21 11:08:50 -0500348 if (_Py_HashSecret_Initialized)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100349 return;
Benjamin Peterson69e97272012-02-21 11:08:50 -0500350 _Py_HashSecret_Initialized = 1;
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100351
352 /*
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100353 Hash randomization is enabled. Generate a per-process secret,
354 using PYTHONHASHSEED if provided.
355 */
356
357 env = Py_GETENV("PYTHONHASHSEED");
Georg Brandl12897d72012-02-20 23:49:29 +0100358 if (env && *env != '\0' && strcmp(env, "random") != 0) {
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100359 char *endptr = env;
360 unsigned long seed;
361 seed = strtoul(env, &endptr, 10);
362 if (*endptr != '\0'
363 || seed > 4294967295UL
364 || (errno == ERANGE && seed == ULONG_MAX))
365 {
366 Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
367 "in range [0; 4294967295]");
368 }
369 if (seed == 0) {
370 /* disable the randomized hash */
371 memset(secret, 0, secret_size);
372 }
373 else {
Christian Heimes985ecdc2013-11-20 11:46:18 +0100374 lcg_urandom(seed, secret, secret_size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100375 }
376 }
377 else {
378#ifdef MS_WINDOWS
Christian Heimes985ecdc2013-11-20 11:46:18 +0100379 (void)win32_urandom(secret, secret_size, 0);
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100380#elif HAVE_GETENTROPY
381 (void)py_getentropy(secret, secret_size, 1);
Christian Heimesaf01f662013-12-21 16:19:10 +0100382#else
Christian Heimes985ecdc2013-11-20 11:46:18 +0100383 dev_urandom_noraise(secret, secret_size);
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100384#endif
385 }
386}
Antoine Pitrou4879a962013-08-31 00:26:02 +0200387
388void
389_PyRandom_Fini(void)
390{
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200391#ifdef MS_WINDOWS
392 if (hCryptProv) {
Tim Goldenb8ac3e12014-05-06 13:29:45 +0100393 CryptReleaseContext(hCryptProv, 0);
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200394 hCryptProv = 0;
395 }
Victor Stinner4d6a3d62014-12-21 01:16:38 +0100396#elif HAVE_GETENTROPY
397 /* nothing to clean */
Victor Stinnerd50c3f32014-05-02 22:06:44 +0200398#else
Antoine Pitrou4879a962013-08-31 00:26:02 +0200399 dev_urandom_close();
400#endif
401}