diff options
| author | Eli Zaretskii | 2016-01-15 11:47:55 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-01-15 11:47:55 +0200 |
| commit | 3ffe81e245d854a694ae1734f1b6a995bdc5e724 (patch) | |
| tree | 2d8fccecc5b404f8fb71e15fe0ea6477a09a1857 /src | |
| parent | fee0526a189f43e8470d78e8374bd425890fbe6f (diff) | |
| download | emacs-3ffe81e245d854a694ae1734f1b6a995bdc5e724.tar.gz emacs-3ffe81e245d854a694ae1734f1b6a995bdc5e724.zip | |
Make 'random' seeds cryptographically secure if possible
* configure.ac: Check for "/dev/urandom".
* src/sysdep.c (init_random) [HAVE_DEV_URANDOM]: Read the stream
for the seed from "/dev/urandom".
[WINDOWSNT]: Obtain the stream for the seed from w32 APIs.
* src/fns.c (Frandom): Update the doc string to indicate that
system entropy is used when available.
* src/w32.c: Include wincrypt.h.
(w32_init_crypt_random, w32_init_random): New functions, use the
CryptGenRandom API.
(globals_of_w32): Initialize w32_crypto_hprov handle to zero.
* src/w32.h (w32_init_random): Add prototype.
* doc/lispref/numbers.texi (Random Numbers): Document more details
about 't' as the argument to 'random'.
* etc/NEWS: Mention that '(random t)' now uses a cryptographically
strong seed if possible.
(Bug#22202)
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 3 | ||||
| -rw-r--r-- | src/sysdep.c | 31 | ||||
| -rw-r--r-- | src/w32.c | 32 | ||||
| -rw-r--r-- | src/w32.h | 3 |
4 files changed, 66 insertions, 3 deletions
| @@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. between `most-negative-fixnum' | |||
| 50 | and `most-positive-fixnum', inclusive, are equally likely. | 50 | and `most-positive-fixnum', inclusive, are equally likely. |
| 51 | 51 | ||
| 52 | With positive integer LIMIT, return random number in interval [0,LIMIT). | 52 | With positive integer LIMIT, return random number in interval [0,LIMIT). |
| 53 | With argument t, set the random number seed from the current time and pid. | 53 | With argument t, set the random number seed from the system's entropy |
| 54 | pool, or from the current time and pid if entropy is unavailable. | ||
| 54 | With a string argument, set the seed based on the string's contents. | 55 | With a string argument, set the seed based on the string's contents. |
| 55 | Other values of LIMIT are ignored. | 56 | Other values of LIMIT are ignored. |
| 56 | 57 | ||
diff --git a/src/sysdep.c b/src/sysdep.c index a78c4c64c81..1fa422947ed 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -2095,8 +2095,35 @@ seed_random (void *seed, ptrdiff_t seed_size) | |||
| 2095 | void | 2095 | void |
| 2096 | init_random (void) | 2096 | init_random (void) |
| 2097 | { | 2097 | { |
| 2098 | struct timespec t = current_timespec (); | 2098 | uintmax_t v; |
| 2099 | uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; | 2099 | struct timespec t; |
| 2100 | bool success = false; | ||
| 2101 | |||
| 2102 | #if HAVE_DEV_URANDOM | ||
| 2103 | FILE *fp = fopen ("/dev/urandom", "rb"); | ||
| 2104 | |||
| 2105 | if (fp) | ||
| 2106 | { | ||
| 2107 | int i; | ||
| 2108 | |||
| 2109 | for (i = 0, v = 0; i < sizeof (uintmax_t); i++) | ||
| 2110 | { | ||
| 2111 | v <<= 8; | ||
| 2112 | v |= fgetc (fp); | ||
| 2113 | } | ||
| 2114 | fclose (fp); | ||
| 2115 | success = true; | ||
| 2116 | } | ||
| 2117 | #elif defined WINDOWSNT | ||
| 2118 | if (w32_init_random (&v, sizeof v) == 0) | ||
| 2119 | success = true; | ||
| 2120 | #endif /* HAVE_DEV_URANDOM || WINDOWSNT */ | ||
| 2121 | if (!success) | ||
| 2122 | { | ||
| 2123 | /* Fall back to current time value + PID. */ | ||
| 2124 | t = current_timespec (); | ||
| 2125 | v = getpid () ^ t.tv_sec ^ t.tv_nsec; | ||
| 2126 | } | ||
| 2100 | seed_random (&v, sizeof v); | 2127 | seed_random (&v, sizeof v); |
| 2101 | } | 2128 | } |
| 2102 | 2129 | ||
| @@ -224,6 +224,8 @@ typedef struct _REPARSE_DATA_BUFFER { | |||
| 224 | 224 | ||
| 225 | #include <iphlpapi.h> /* should be after winsock2.h */ | 225 | #include <iphlpapi.h> /* should be after winsock2.h */ |
| 226 | 226 | ||
| 227 | #include <wincrypt.h> | ||
| 228 | |||
| 227 | #include <c-strcase.h> | 229 | #include <c-strcase.h> |
| 228 | 230 | ||
| 229 | #include "w32.h" | 231 | #include "w32.h" |
| @@ -2093,6 +2095,34 @@ init_user_info (void) | |||
| 2093 | CloseHandle (token); | 2095 | CloseHandle (token); |
| 2094 | } | 2096 | } |
| 2095 | 2097 | ||
| 2098 | static HCRYPTPROV w32_crypto_hprov; | ||
| 2099 | static int | ||
| 2100 | w32_init_crypt_random (void) | ||
| 2101 | { | ||
| 2102 | if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL, | ||
| 2103 | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) | ||
| 2104 | { | ||
| 2105 | DebPrint (("CryptAcquireContext failed with error %x\n", | ||
| 2106 | GetLastError ())); | ||
| 2107 | w32_crypto_hprov = 0; | ||
| 2108 | return -1; | ||
| 2109 | } | ||
| 2110 | return 0; | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | int | ||
| 2114 | w32_init_random (void *buf, ptrdiff_t buflen) | ||
| 2115 | { | ||
| 2116 | if (!w32_crypto_hprov) | ||
| 2117 | w32_init_crypt_random (); | ||
| 2118 | if (w32_crypto_hprov) | ||
| 2119 | { | ||
| 2120 | if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf)) | ||
| 2121 | return 0; | ||
| 2122 | } | ||
| 2123 | return -1; | ||
| 2124 | } | ||
| 2125 | |||
| 2096 | int | 2126 | int |
| 2097 | random (void) | 2127 | random (void) |
| 2098 | { | 2128 | { |
| @@ -9410,6 +9440,8 @@ globals_of_w32 (void) | |||
| 9410 | extern void dynlib_reset_last_error (void); | 9440 | extern void dynlib_reset_last_error (void); |
| 9411 | dynlib_reset_last_error (); | 9441 | dynlib_reset_last_error (); |
| 9412 | #endif | 9442 | #endif |
| 9443 | |||
| 9444 | w32_crypto_hprov = (HCRYPTPROV)0; | ||
| 9413 | } | 9445 | } |
| 9414 | 9446 | ||
| 9415 | /* For make-serial-process */ | 9447 | /* For make-serial-process */ |
| @@ -222,6 +222,9 @@ extern int w32_memory_info (unsigned long long *, unsigned long long *, | |||
| 222 | /* Compare 2 UTF-8 strings in locale-dependent fashion. */ | 222 | /* Compare 2 UTF-8 strings in locale-dependent fashion. */ |
| 223 | extern int w32_compare_strings (const char *, const char *, char *, int); | 223 | extern int w32_compare_strings (const char *, const char *, char *, int); |
| 224 | 224 | ||
| 225 | /* Return a cryptographically secure seed for PRNG. */ | ||
| 226 | extern int w32_init_random (void *, ptrdiff_t); | ||
| 227 | |||
| 225 | #ifdef HAVE_GNUTLS | 228 | #ifdef HAVE_GNUTLS |
| 226 | #include <gnutls/gnutls.h> | 229 | #include <gnutls/gnutls.h> |
| 227 | 230 | ||