aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2016-01-15 11:47:55 +0200
committerEli Zaretskii2016-01-15 11:47:55 +0200
commit3ffe81e245d854a694ae1734f1b6a995bdc5e724 (patch)
tree2d8fccecc5b404f8fb71e15fe0ea6477a09a1857
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)
-rw-r--r--configure.ac16
-rw-r--r--doc/lispref/numbers.texi4
-rw-r--r--etc/NEWS8
-rw-r--r--src/fns.c3
-rw-r--r--src/sysdep.c31
-rw-r--r--src/w32.c32
-rw-r--r--src/w32.h3
7 files changed, 93 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 8c01abac9c6..6c9b621dd82 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4153,6 +4153,22 @@ fi
4153 4153
4154AC_TYPE_MBSTATE_T 4154AC_TYPE_MBSTATE_T
4155 4155
4156AC_MSG_CHECKING([whether "/dev/urandom" is available])
4157dev_urandom=no
4158dnl MSYS, being a Cygwin fork, thinks "/dev/urandom" does exist, so
4159dnl don't check this for the MinGW builds.
4160if test "${opsys}" != "mingw32"; then
4161 if test -r "/dev/urandom"; then
4162 AC_DEFINE(HAVE_DEV_URANDOM, 1, [Define if the system supports the "/dev/urandom" device.])
4163 dev_urandom=yes
4164 fi
4165fi
4166if test $dev_urandom = yes; then
4167 AC_MSG_RESULT(yes)
4168else
4169 AC_MSG_RESULT(no)
4170fi
4171
4156dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear 4172dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear
4157dnl how the tty code is related to POSIX and/or other versions of termios. 4173dnl how the tty code is related to POSIX and/or other versions of termios.
4158dnl The following looks like a useful start. 4174dnl The following looks like a useful start.
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index 20d3c4290f3..3a9483af967 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -1252,7 +1252,9 @@ any integer representable in Lisp, i.e., an integer between
1252(@pxref{Integer Basics}). 1252(@pxref{Integer Basics}).
1253 1253
1254If @var{limit} is @code{t}, it means to choose a new seed as if Emacs 1254If @var{limit} is @code{t}, it means to choose a new seed as if Emacs
1255were restarting. 1255were restarting. The new seed will be set from the system entropy, if
1256that is available, or from the current time and Emacs process's PID
1257(@pxref{System Environment, emacs-pid}) if not.
1256 1258
1257If @var{limit} is a string, it means to choose a new seed based on the 1259If @var{limit} is a string, it means to choose a new seed based on the
1258string's contents. 1260string's contents.
diff --git a/etc/NEWS b/etc/NEWS
index 21aee20089e..9e635798c58 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -214,6 +214,14 @@ for use in Emacs bug reports.
214hiding character but the default `.' can be used by let-binding the 214hiding character but the default `.' can be used by let-binding the
215variable `read-hide-char'. 215variable `read-hide-char'.
216 216
217+++
218** The Emacs pseudo-random number generator can be securely seeded.
219On system where Emacs can access the system entropy or some other
220cryptographically secure random stream, it now uses that when `random'
221is called with its argument `t'. This allows cryptographically strong
222random values; in particular, the Emacs server now uses this facility
223to produce its authentication key.
224
217--- 225---
218** New input methods: `tamil-dvorak' and `programmer-dvorak'. 226** New input methods: `tamil-dvorak' and `programmer-dvorak'.
219 227
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