aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2016-01-15 11:47:55 +0200
committerEli Zaretskii2016-01-15 11:47:55 +0200
commit3ffe81e245d854a694ae1734f1b6a995bdc5e724 (patch)
tree2d8fccecc5b404f8fb71e15fe0ea6477a09a1857 /src
parentfee0526a189f43e8470d78e8374bd425890fbe6f (diff)
downloademacs-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.c3
-rw-r--r--src/sysdep.c31
-rw-r--r--src/w32.c32
-rw-r--r--src/w32.h3
4 files changed, 66 insertions, 3 deletions
diff --git a/src/fns.c b/src/fns.c
index 977229b97b7..19fa44086c9 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. between `most-negative-fixnum'
50and `most-positive-fixnum', inclusive, are equally likely. 50and `most-positive-fixnum', inclusive, are equally likely.
51 51
52With positive integer LIMIT, return random number in interval [0,LIMIT). 52With positive integer LIMIT, return random number in interval [0,LIMIT).
53With argument t, set the random number seed from the current time and pid. 53With argument t, set the random number seed from the system's entropy
54pool, or from the current time and pid if entropy is unavailable.
54With a string argument, set the seed based on the string's contents. 55With a string argument, set the seed based on the string's contents.
55Other values of LIMIT are ignored. 56Other 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)
2095void 2095void
2096init_random (void) 2096init_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
diff --git a/src/w32.c b/src/w32.c
index ea3a9dafad5..7884bad619c 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -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
2098static HCRYPTPROV w32_crypto_hprov;
2099static int
2100w32_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
2113int
2114w32_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
2096int 2126int
2097random (void) 2127random (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 */
diff --git a/src/w32.h b/src/w32.h
index 501056d38c6..ba3fec8b7e6 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -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. */
223extern int w32_compare_strings (const char *, const char *, char *, int); 223extern int w32_compare_strings (const char *, const char *, char *, int);
224 224
225/* Return a cryptographically secure seed for PRNG. */
226extern 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