random: Add jitter RND based entropy collector.
authorWerner Koch <wk@gnupg.org>
Wed, 14 Jun 2017 12:03:05 +0000 (14:03 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 14 Jun 2017 12:07:23 +0000 (14:07 +0200)
* 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>
AUTHORS
configure.ac
random/Makefile.am
random/rand-internal.h
random/rndjent.c [new file with mode: 0644]
random/rndlinux.c
random/rndw32.c

diff --git a/AUTHORS b/AUTHORS
index b80d43e..c1e813d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
index 7ea0b6a..d36673f 100644 (file)
@@ -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])
index 92aba20..aaf205e 100644 (file)
@@ -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) `
index 8c8623e..7a798e9 100644 (file)
@@ -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 (file)
index 0000000..fa3bb99
--- /dev/null
@@ -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))
+
+
+\f
+/*
+ * 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 */
+
+\f
+/*
+ * 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;
+}
index d3a144a..f1548fb 100644 (file)
@@ -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)
         {
index 1dec5a7..7e9ac50 100644 (file)
@@ -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;
 }