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)
This commit is contained in:
parent
fee0526a18
commit
3ffe81e245
7 changed files with 93 additions and 4 deletions
16
configure.ac
16
configure.ac
|
@ -4153,6 +4153,22 @@ fi
|
|||
|
||||
AC_TYPE_MBSTATE_T
|
||||
|
||||
AC_MSG_CHECKING([whether "/dev/urandom" is available])
|
||||
dev_urandom=no
|
||||
dnl MSYS, being a Cygwin fork, thinks "/dev/urandom" does exist, so
|
||||
dnl don't check this for the MinGW builds.
|
||||
if test "${opsys}" != "mingw32"; then
|
||||
if test -r "/dev/urandom"; then
|
||||
AC_DEFINE(HAVE_DEV_URANDOM, 1, [Define if the system supports the "/dev/urandom" device.])
|
||||
dev_urandom=yes
|
||||
fi
|
||||
fi
|
||||
if test $dev_urandom = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear
|
||||
dnl how the tty code is related to POSIX and/or other versions of termios.
|
||||
dnl The following looks like a useful start.
|
||||
|
|
|
@ -1252,7 +1252,9 @@ any integer representable in Lisp, i.e., an integer between
|
|||
(@pxref{Integer Basics}).
|
||||
|
||||
If @var{limit} is @code{t}, it means to choose a new seed as if Emacs
|
||||
were restarting.
|
||||
were restarting. The new seed will be set from the system entropy, if
|
||||
that is available, or from the current time and Emacs process's PID
|
||||
(@pxref{System Environment, emacs-pid}) if not.
|
||||
|
||||
If @var{limit} is a string, it means to choose a new seed based on the
|
||||
string's contents.
|
||||
|
|
8
etc/NEWS
8
etc/NEWS
|
@ -214,6 +214,14 @@ for use in Emacs bug reports.
|
|||
hiding character but the default `.' can be used by let-binding the
|
||||
variable `read-hide-char'.
|
||||
|
||||
+++
|
||||
** The Emacs pseudo-random number generator can be securely seeded.
|
||||
On system where Emacs can access the system entropy or some other
|
||||
cryptographically secure random stream, it now uses that when `random'
|
||||
is called with its argument `t'. This allows cryptographically strong
|
||||
random values; in particular, the Emacs server now uses this facility
|
||||
to produce its authentication key.
|
||||
|
||||
---
|
||||
** New input methods: `tamil-dvorak' and `programmer-dvorak'.
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. between `most-negative-fixnum'
|
|||
and `most-positive-fixnum', inclusive, are equally likely.
|
||||
|
||||
With positive integer LIMIT, return random number in interval [0,LIMIT).
|
||||
With argument t, set the random number seed from the current time and pid.
|
||||
With argument t, set the random number seed from the system's entropy
|
||||
pool, or from the current time and pid if entropy is unavailable.
|
||||
With a string argument, set the seed based on the string's contents.
|
||||
Other values of LIMIT are ignored.
|
||||
|
||||
|
|
31
src/sysdep.c
31
src/sysdep.c
|
@ -2095,8 +2095,35 @@ seed_random (void *seed, ptrdiff_t seed_size)
|
|||
void
|
||||
init_random (void)
|
||||
{
|
||||
struct timespec t = current_timespec ();
|
||||
uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec;
|
||||
uintmax_t v;
|
||||
struct timespec t;
|
||||
bool success = false;
|
||||
|
||||
#if HAVE_DEV_URANDOM
|
||||
FILE *fp = fopen ("/dev/urandom", "rb");
|
||||
|
||||
if (fp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0, v = 0; i < sizeof (uintmax_t); i++)
|
||||
{
|
||||
v <<= 8;
|
||||
v |= fgetc (fp);
|
||||
}
|
||||
fclose (fp);
|
||||
success = true;
|
||||
}
|
||||
#elif defined WINDOWSNT
|
||||
if (w32_init_random (&v, sizeof v) == 0)
|
||||
success = true;
|
||||
#endif /* HAVE_DEV_URANDOM || WINDOWSNT */
|
||||
if (!success)
|
||||
{
|
||||
/* Fall back to current time value + PID. */
|
||||
t = current_timespec ();
|
||||
v = getpid () ^ t.tv_sec ^ t.tv_nsec;
|
||||
}
|
||||
seed_random (&v, sizeof v);
|
||||
}
|
||||
|
||||
|
|
32
src/w32.c
32
src/w32.c
|
@ -224,6 +224,8 @@ typedef struct _REPARSE_DATA_BUFFER {
|
|||
|
||||
#include <iphlpapi.h> /* should be after winsock2.h */
|
||||
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include <c-strcase.h>
|
||||
|
||||
#include "w32.h"
|
||||
|
@ -2093,6 +2095,34 @@ init_user_info (void)
|
|||
CloseHandle (token);
|
||||
}
|
||||
|
||||
static HCRYPTPROV w32_crypto_hprov;
|
||||
static int
|
||||
w32_init_crypt_random (void)
|
||||
{
|
||||
if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
{
|
||||
DebPrint (("CryptAcquireContext failed with error %x\n",
|
||||
GetLastError ()));
|
||||
w32_crypto_hprov = 0;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
w32_init_random (void *buf, ptrdiff_t buflen)
|
||||
{
|
||||
if (!w32_crypto_hprov)
|
||||
w32_init_crypt_random ();
|
||||
if (w32_crypto_hprov)
|
||||
{
|
||||
if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
random (void)
|
||||
{
|
||||
|
@ -9410,6 +9440,8 @@ globals_of_w32 (void)
|
|||
extern void dynlib_reset_last_error (void);
|
||||
dynlib_reset_last_error ();
|
||||
#endif
|
||||
|
||||
w32_crypto_hprov = (HCRYPTPROV)0;
|
||||
}
|
||||
|
||||
/* For make-serial-process */
|
||||
|
|
|
@ -222,6 +222,9 @@ extern int w32_memory_info (unsigned long long *, unsigned long long *,
|
|||
/* Compare 2 UTF-8 strings in locale-dependent fashion. */
|
||||
extern int w32_compare_strings (const char *, const char *, char *, int);
|
||||
|
||||
/* Return a cryptographically secure seed for PRNG. */
|
||||
extern int w32_init_random (void *, ptrdiff_t);
|
||||
|
||||
#ifdef HAVE_GNUTLS
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue