diff options
author | Werner Koch <wk@gnupg.org> | 2017-06-14 14:03:05 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2017-06-14 14:07:23 +0200 |
commit | f5e7763ddca59dcd9ac9f2f4d50cb41b14a34a9e (patch) | |
tree | a26b001fcfa77b5442033141a47f750ce76a0fc9 | |
parent | 6c882fb1fdb6c7cba2215fa7391110d63e24b9dc (diff) | |
download | libgcrypt-f5e7763ddca59dcd9ac9f2f4d50cb41b14a34a9e.tar.gz |
random: Add jitter RND based entropy collector.
* random/rndjent.c: New.
* random/rndlinux.c (_gcry_rndlinux_gather_random): Use rndjent.
* random/rndw32.c (_gcry_rndw32_gather_random): Use rndjent.
(slow_gatherer): Fix compiler warning.
* random/Makefile.am (librandom_la_SOURCES): Add rndjent.c
(EXTRA_librandom_la_SOURCES): Add jitterentropy-base.c and
jitterentropy.h.
(rndjent.o, rndjent.lo): New rules.
* configure.ac: New option --disbale-jent-support
(ENABLE_JENT_SUPPORT): New ac-define.
Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | random/Makefile.am | 20 | ||||
-rw-r--r-- | random/rand-internal.h | 8 | ||||
-rw-r--r-- | random/rndjent.c | 208 | ||||
-rw-r--r-- | random/rndlinux.c | 15 | ||||
-rw-r--r-- | random/rndw32.c | 12 |
7 files changed, 274 insertions, 6 deletions
@@ -30,13 +30,14 @@ List of Copyright holders Copyright (C) 1996-2006 Peter Gutmann, Matt Thomlinson and Blake Coverett Copyright (C) 2003 Nikos Mavroyanopoulos Copyright (C) 2006-2007 NTT (Nippon Telegraph and Telephone Corporation) - Copyright (C) 2012-2016 g10 Code GmbH + Copyright (C) 2012-2017 g10 Code GmbH Copyright (C) 2012 Simon Josefsson, Niels Möller Copyright (c) 2012 Intel Corporation Copyright (C) 2013 Christian Grothoff Copyright (C) 2013-2016 Jussi Kivilinna Copyright (C) 2013-2014 Dmitry Eremin-Solenikov Copyright (C) 2014 Stephan Mueller + Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik Authors with a FSF copyright assignment diff --git a/configure.ac b/configure.ac index 7ea0b6a6..d36673f3 100644 --- a/configure.ac +++ b/configure.ac @@ -577,6 +577,14 @@ if test "$use_hmac_binary_check" = yes ; then fi +# Implementation of the --disable-jent-support switch. +AC_MSG_CHECKING([whether jitter entropy support is requested]) +AC_ARG_ENABLE(jent-support, + AC_HELP_STRING([--disable-jent-support], + [Disable support for the Jitter entropy collector]), + jentsupport=$enableval,jentsupport=yes) +AC_MSG_RESULT($jentsupport) + # Implementation of the --disable-padlock-support switch. AC_MSG_CHECKING([whether padlock support is requested]) AC_ARG_ENABLE(padlock-support, @@ -1185,6 +1193,7 @@ if test "$mpi_cpu_arch" != "x86" ; then avxsupport="n/a" avx2support="n/a" padlocksupport="n/a" + jentsupport="n/a" drngsupport="n/a" fi @@ -1980,6 +1989,10 @@ if test x"$armcryptosupport" = xyes ; then AC_DEFINE(ENABLE_ARM_CRYPTO_SUPPORT,1, [Enable support for ARMv8 Crypto Extension instructions.]) fi +if test x"$jentsupport" = xyes ; then + AC_DEFINE(ENABLE_JENT_SUPPORT, 1, + [Enable support for the jitter entropy collector.]) +fi if test x"$padlocksupport" = xyes ; then AC_DEFINE(ENABLE_PADLOCK_SUPPORT, 1, [Enable support for the PadLock engine.]) @@ -2619,6 +2632,7 @@ GCRY_MSG_WRAP([Enabled digest algorithms:],[$enabled_digests]) GCRY_MSG_WRAP([Enabled kdf algorithms: ],[$enabled_kdfs]) GCRY_MSG_WRAP([Enabled pubkey algorithms:],[$enabled_pubkey_ciphers]) GCRY_MSG_SHOW([Random number generator: ],[$random]) +GCRY_MSG_SHOW([Try using jitter entropy: ],[$jentsupport]) GCRY_MSG_SHOW([Using linux capabilities: ],[$use_capabilities]) GCRY_MSG_SHOW([Try using Padlock crypto: ],[$padlocksupport]) GCRY_MSG_SHOW([Try using AES-NI crypto: ],[$aesnisupport]) diff --git a/random/Makefile.am b/random/Makefile.am index 92aba201..aaf205ee 100644 --- a/random/Makefile.am +++ b/random/Makefile.am @@ -36,6 +36,7 @@ rand-internal.h \ random-csprng.c \ random-drbg.c \ random-system.c \ +rndjent.c \ rndhw.c if USE_RANDOM_DAEMON @@ -48,4 +49,21 @@ rndlinux.c \ rndegd.c \ rndunix.c \ rndw32.c \ -rndw32ce.c +rndw32ce.c \ +jitterentropy-base.c jitterentropy.h + + +# The rndjent module needs to be compiled without optimization. */ +if ENABLE_O_FLAG_MUNGING +o_flag_munging = sed -e 's/-O\([1-9s][1-9s]*\)/-O0/' -e 's/-Ofast/-O0/g' +else +o_flag_munging = cat +endif + +rndjent.o: $(srcdir)/rndjent.c \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +rndjent.lo: $(srcdir)/rndjent.c \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` diff --git a/random/rand-internal.h b/random/rand-internal.h index 8c8623ed..7a798e98 100644 --- a/random/rand-internal.h +++ b/random/rand-internal.h @@ -98,7 +98,7 @@ int _gcry_rndunix_gather_random (void (*add) (const void *, size_t, enum random_origins origin, size_t length, int level); -/*-- rndelg.c --*/ +/*-- rndegd.c --*/ int _gcry_rndegd_gather_random (void (*add) (const void *, size_t, enum random_origins), enum random_origins origin, @@ -123,6 +123,12 @@ void _gcry_rndw32ce_gather_random_fast (void (*add)(const void*, size_t, enum random_origins), enum random_origins origin ); +/*-- rndjent.c --*/ +size_t _gcry_rndjent_poll (void (*add)(const void*, + size_t, enum random_origins), + enum random_origins origin, + size_t length); + /*-- rndhw.c --*/ int _gcry_rndhw_failed_p (void); void _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, diff --git a/random/rndjent.c b/random/rndjent.c new file mode 100644 index 00000000..fa3bb99a --- /dev/null +++ b/random/rndjent.c @@ -0,0 +1,208 @@ +/* rndjent.c - Driver for the jitterentropy module. + * Copyright (C) 2017 g10 Code GmbH + * Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif + +#include "types.h" +#include "g10lib.h" +#include "../cipher/bithelp.h" +#include "rand-internal.h" + +/* + * Decide whether we can support jent at compile time. + */ +#undef USE_JENT +#ifdef ENABLE_JENT_SUPPORT +# if defined (__i386__) || defined(__x86_64__) +# define USE_JENT 1 +# endif +#endif /*ENABLE_JENT_SUPPORT*/ + + +#ifdef USE_JENT + +/* When using the libgcrypt secure memory mechanism, all precautions + * are taken to protect our state. If the user disables secmem during + * runtime, it is his decision and we thus try not to overrule his + * decision for less memory protection. */ +#define JENT_CPU_JITTERENTROPY_SECURE_MEMORY 1 +#define jent_zalloc(n) _gcry_calloc_secure (1, (n)) + + + +/* + * Libgcrypt specific platform dependent functions. + */ + + +static void +jent_get_nstime(u64 *out) +{ + u32 t_eax, t_edx; + + asm volatile (".byte 0x0f,0x31\n\t" + : "=a" (t_eax), "=d" (t_edx) + ); + *out = (((u64)t_edx << 32) | t_eax); +} + + +static GPGRT_INLINE void +jent_zfree (void *ptr, unsigned int len) +{ + if (ptr) + { + wipememory (ptr, len); + _gcry_free (ptr); + } +} + +static GPGRT_INLINE int +jent_fips_enabled(void) +{ + return fips_mode(); +} + + +/* + * We source include the actual jitter entropy code. Note that the + * included code has been slightly changed from the Linux kernel + * version for namespace reasons. We define MODULE so that the + * EXPORT_SYMBOL macro will not be used. + */ +#undef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +/* Uncomment the next line to build with statistics. */ +/* #define CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT 1 */ + +#undef MODULE +#define MODULE 1 + +#ifndef HAVE_STDINT_H +# error This module needs stdint.h - try ./configure --disable-jent-support +#endif +#include "jitterentropy-base.c" + + +/* This is the lock we use to serialize access to this RNG. The extra + * integer variable is only used to check the locking state; that is, + * it is not meant to be thread-safe but merely as a failsafe feature + * to assert proper locking. */ +GPGRT_LOCK_DEFINE (jent_rng_lock); +static int jent_rng_is_locked; + +/* This flag tracks whether the RNG has been initialized - either + * with error or with success. Protected by JENT_RNG_LOCK. */ +static int jent_rng_is_initialized; + +/* Our collector. The RNG is in a working state if its value is not + * NULL. Protected by JENT_RNG_LOCK. */ +struct rand_data *jent_rng_collector; + + +/* Acquire the jent_rng_lock. */ +static void +lock_rng (void) +{ + gpg_err_code_t rc; + + rc = gpgrt_lock_lock (&jent_rng_lock); + if (rc) + log_fatal ("failed to acquire the Jent RNG lock: %s\n", + gpg_strerror (rc)); + jent_rng_is_locked = 1; +} + + +/* Release the jent_rng_lock. */ +static void +unlock_rng (void) +{ + gpg_err_code_t rc; + + jent_rng_is_locked = 0; + rc = gpgrt_lock_unlock (&jent_rng_lock); + if (rc) + log_fatal ("failed to release the Jent RNG lock: %s\n", + gpg_strerror (rc)); +} + +#endif /* USE_JENT */ + + +/* + * The API used by the high level code. + */ + +/* Read up to LENGTH bytes from a jitter RNG and return the number of + * bytes actually read. */ +size_t +_gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, size_t length) +{ + size_t nbytes = 0; + + (void)add; + (void)origin; + +#ifdef USE_JENT + if ((_gcry_get_hw_features () & HWF_INTEL_RDTSC)) + { + lock_rng (); + + if (!jent_rng_is_initialized) + { + /* Auto-initialize. */ + jent_rng_is_initialized = 1; + jent_entropy_collector_free (jent_rng_collector); + jent_rng_collector = NULL; + if (!jent_entropy_init ()) + jent_rng_collector = jent_entropy_collector_alloc (1, 0); + } + + if (jent_rng_collector) + { + /* We have a working JENT. */ + char buffer[256]; + + while (length) + { + int rc; + size_t n = length < sizeof(buffer)? length : sizeof (buffer); + + rc = jent_read_entropy (jent_rng_collector, buffer, n); + if (rc < 0) + break; + (*add) (buffer, rc, origin); + length -= rc; + nbytes += rc; + } + } + + unlock_rng (); + } +#endif + + return nbytes; +} diff --git a/random/rndlinux.c b/random/rndlinux.c index d3a144a4..f1548fbf 100644 --- a/random/rndlinux.c +++ b/random/rndlinux.c @@ -158,6 +158,19 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, if (length > 1) length -= n_hw; + /* When using a blocking random generator try to get some entropy + * from the jitter based RNG. In this case we take up to 50% of the + * remaining requested bytes. */ + if (level >= GCRY_VERY_STRONG_RANDOM) + { + n_hw = _gcry_rndjent_poll (add, origin, length/2); + if (n_hw > length/2) + n_hw = length/2; + if (length > 1) + length -= n_hw; + } + + /* Open the requested device. The first time a device is to be opened we fail with a fatal error if the device does not exists. In case the device has ever been closed, further open requests @@ -165,7 +178,7 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, that we always require the device to be existent but want a more graceful behaviour if the rarely needed close operation has been used and the device needs to be re-opened later. */ - if (level >= 2) + if (level >= GCRY_VERY_STRONG_RANDOM) { if (fd_random == -1) { diff --git a/random/rndw32.c b/random/rndw32.c index 1dec5a7e..7e9ac50e 100644 --- a/random/rndw32.c +++ b/random/rndw32.c @@ -584,8 +584,8 @@ slow_gatherer ( void (*add)(const void*, size_t, enum random_origins), if (hNetAPI32 && !pNetStatisticsGet (NULL, - is_workstation ? L"LanmanWorkstation" : - L"LanmanServer", 0, 0, &lpBuffer)) + (LPWSTR)(is_workstation ? L"LanmanWorkstation" : + L"LanmanServer"), 0, 0, &lpBuffer)) { if ( debug_me ) log_debug ("rndw32#slow_gatherer: get netstats\n" ); @@ -776,6 +776,7 @@ _gcry_rndw32_gather_random (void (*add)(const void*, size_t, size_t length, int level ) { static int is_initialized; + size_t n; if (!level) return 0; @@ -808,6 +809,13 @@ _gcry_rndw32_gather_random (void (*add)(const void*, size_t, slow_gatherer (add, origin); + /* Round requested LENGTH up to full 32 bytes. */ + n = _gcry_rndjent_poll (add, origin, ((length + 31) / 32) * 32); + + if (debug_me) + log_debug ("rndw32#gather_random: jent contributed extra %u bytes\n", + (unsigned int)n); + return 0; } |