summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/random/random-csprng.c
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
committerSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
commit0e752a6e215aee21dc73da097c3225495d54a5b6 (patch)
treeb81be02cbf2f06aebf322ac4a5d014b44176bba5 /libotr/libgcrypt-1.8.7/random/random-csprng.c
parent7754076c715285173311a1b6811ce377950e18a6 (diff)
Add libotr/etc sources
Diffstat (limited to 'libotr/libgcrypt-1.8.7/random/random-csprng.c')
-rw-r--r--libotr/libgcrypt-1.8.7/random/random-csprng.c1363
1 files changed, 1363 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/random/random-csprng.c b/libotr/libgcrypt-1.8.7/random/random-csprng.c
new file mode 100644
index 0000000..6073ee3
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/random/random-csprng.c
@@ -0,0 +1,1363 @@
+/* random-csprng.c - CSPRNG style random number generator (libgcrypt classic)
+ * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ *               2007, 2008, 2010, 2012  Free Software Foundation, Inc.
+ *
+ * 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/>.
+ */
+
+/*
+   This random number generator is modelled after the one described in
+   Peter Gutmann's 1998 Usenix Security Symposium paper: "Software
+   Generation of Practically Strong Random Numbers".  See also chapter
+   6 in his book "Cryptographic Security Architecture", New York,
+   2004, ISBN 0-387-95387-6.
+
+   Note that the acronym CSPRNG stands for "Continuously Seeded
+   PseudoRandom Number Generator" as used in Peter's implementation of
+   the paper and not only for "Cryptographically Secure PseudoRandom
+   Number Generator".
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#ifdef	HAVE_GETHRTIME
+#include <sys/times.h>
+#endif
+#ifdef HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+#endif
+#ifdef __MINGW32__
+#include <process.h>
+#endif
+#include "g10lib.h"
+#include "random.h"
+#include "rand-internal.h"
+#include "cipher.h"         /* _gcry_sha1_hash_buffer  */
+#include "../cipher/sha1.h" /* _gcry_sha1_mixblock     */
+
+#ifndef RAND_MAX   /* For SunOS. */
+#define RAND_MAX 32767
+#endif
+
+/* Check whether we can lock the seed file read write. */
+#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
+#define LOCK_SEED_FILE 1
+#else
+#define LOCK_SEED_FILE 0
+#endif
+
+/* Define the constant we use for transforming the pool at read-out. */
+#if SIZEOF_UNSIGNED_LONG == 8
+#define ADD_VALUE 0xa5a5a5a5a5a5a5a5
+#elif SIZEOF_UNSIGNED_LONG == 4
+#define ADD_VALUE 0xa5a5a5a5
+#else
+#error weird size for an unsigned long
+#endif
+
+/* Contstants pertaining to the hash pool. */
+#define BLOCKLEN  64   /* Hash this amount of bytes... */
+#define DIGESTLEN 20   /* ... into a digest of this length (sha-1). */
+/* POOLBLOCKS is the number of digests which make up the pool.  */
+#define POOLBLOCKS 30
+/* POOLSIZE must be a multiple of the digest length to make the AND
+   operations faster, the size should also be a multiple of unsigned
+   long.  */
+#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
+#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
+#error Please make sure that poolsize is a multiple of unsigned long
+#endif
+#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
+
+
+/* RNDPOOL is the pool we use to collect the entropy and to stir it
+   up.  Its allocated size is POOLSIZE+BLOCKLEN.  Note that this is
+   also an indication on whether the module has been fully
+   initialized. */
+static unsigned char *rndpool;
+
+/* KEYPOOL is used as a scratch copy to read out random from RNDPOOL.
+   Its allocated size is also POOLSIZE+BLOCKLEN.  */
+static unsigned char *keypool;
+
+/* This is the offset into RNDPOOL where the next random bytes are to
+   be mixed in.  */
+static size_t pool_writepos;
+
+/* When reading data out of KEYPOOL, we start the read at different
+   positions.  This variable keeps track on where to read next.  */
+static size_t pool_readpos;
+
+/* This flag is set to true as soon as the pool has been completely
+   filled the first time.  This may happen either by reading a seed
+   file or by adding enough entropy.  */
+static int pool_filled;
+
+/* This counter is used to track whether the initial seeding has been
+   done with enough bytes from a reliable entropy source.  */
+static size_t pool_filled_counter;
+
+/* If random of level GCRY_VERY_STRONG_RANDOM has been requested we
+   have stricter requirements on what kind of entropy is in the pool.
+   In particular POOL_FILLED is not sufficient.  Thus we add some
+   extra seeding and set this flag to true if the extra seeding has
+   been done.  */
+static int did_initial_extra_seeding;
+
+/* This variable is used to estimated the amount of fresh entropy
+   available in RNDPOOL.  */
+static int pool_balance;
+
+/* After a mixing operation this variable will be set to true and
+   cleared if new entropy has been added or a remix is required for
+   other reasons.  */
+static int just_mixed;
+
+/* The name of the seed file or NULL if no seed file has been defined.
+   The seed file needs to be registered at initialiation time.  We
+   keep a malloced copy here.  */
+static char *seed_file_name;
+
+/* If a seed file has been registered and maybe updated on exit this
+   flag set. */
+static int allow_seed_file_update;
+
+/* Option flag set at initialiation time to force allocation of the
+   pool in secure memory.  */
+static int secure_alloc;
+
+/* This function pointer is set to the actual entropy gathering
+   function during initialization.  After initialization it is
+   guaranteed to point to function.  (On systems without a random
+   gatherer module a dummy function is used).*/
+static int (*slow_gather_fnc)(void (*)(const void*, size_t,
+                                       enum random_origins),
+                              enum random_origins, size_t, int);
+
+/* This function is set to the actual fast entropy gathering function
+   during initialization.  If it is NULL, no such function is
+   available. */
+static void (*fast_gather_fnc)(void (*)(const void*, size_t,
+                                        enum random_origins),
+                               enum random_origins);
+
+
+/* Option flag useful for debugging and the test suite.  If set
+   requests for very strong random are degraded to strong random.  Not
+   used by regular applications.  */
+static int quick_test;
+
+/* This is the lock we use to protect all pool operations.  */
+GPGRT_LOCK_DEFINE (pool_lock);
+
+/* This is a helper for assert calls.  These calls are used to assert
+   that functions are called in a locked state.  It is not meant to be
+   thread-safe but as a method to get aware of missing locks in the
+   test suite.  */
+static int pool_is_locked;
+
+
+/* We keep some counters in this structure for the sake of the
+   _gcry_random_dump_stats () function.  */
+static struct
+{
+  unsigned long mixrnd;
+  unsigned long mixkey;
+  unsigned long slowpolls;
+  unsigned long fastpolls;
+  unsigned long getbytes1;
+  unsigned long ngetbytes1;
+  unsigned long getbytes2;
+  unsigned long ngetbytes2;
+  unsigned long addbytes;
+  unsigned long naddbytes;
+} rndstats;
+
+
+
+/* --- Stuff pertaining to the random daemon support. --- */
+#ifdef USE_RANDOM_DAEMON
+
+/* If ALLOW_DAEMON is true, the module will try to use the random
+   daemon first.  If the daemon has failed, this variable is set to
+   back to false and the code continues as normal.  Note, we don't
+   test this flag in a locked state because a wrong value does not
+   harm and the trhead will find out itself that the daemon does not
+   work and set it (again) to false.  */
+static int allow_daemon;
+
+/* During initialization, the user may set a non-default socket name
+   for accessing the random daemon.  If this value is NULL, the
+   default name will be used. */
+static char *daemon_socket_name;
+
+#endif /*USE_RANDOM_DAEMON*/
+
+
+
+/* ---  Prototypes  --- */
+static void read_pool (byte *buffer, size_t length, int level );
+static void add_randomness (const void *buffer, size_t length,
+                            enum random_origins origin);
+static void random_poll (void);
+static void do_fast_random_poll (void);
+static int (*getfnc_gather_random (void))(void (*)(const void*, size_t,
+                                                   enum random_origins),
+                                          enum random_origins, size_t, int);
+static void (*getfnc_fast_random_poll (void))(void (*)(const void*, size_t,
+                                                       enum random_origins),
+                                              enum random_origins);
+static void read_random_source (enum random_origins origin,
+                                size_t length, int level);
+
+
+
+/* ---  Functions  --- */
+
+
+/* Basic initialization which is required to initialize mutexes and
+   such.  It does not run a full initialization so that the filling of
+   the random pool can be delayed until it is actually needed.  We
+   assume that this function is used before any concurrent access
+   happens. */
+static void
+initialize_basics(void)
+{
+  static int initialized;
+
+  if (!initialized)
+    {
+      initialized = 1;
+
+#ifdef USE_RANDOM_DAEMON
+      _gcry_daemon_initialize_basics ();
+#endif /*USE_RANDOM_DAEMON*/
+
+      /* Make sure that we are still using the values we have
+         traditionally used for the random levels.  */
+      gcry_assert (GCRY_WEAK_RANDOM == 0
+                   && GCRY_STRONG_RANDOM == 1
+                   && GCRY_VERY_STRONG_RANDOM == 2);
+    }
+}
+
+/* Take the pool lock. */
+static void
+lock_pool (void)
+{
+  int err;
+
+  err = gpgrt_lock_lock (&pool_lock);
+  if (err)
+    log_fatal ("failed to acquire the pool lock: %s\n", gpg_strerror (err));
+  pool_is_locked = 1;
+}
+
+/* Release the pool lock. */
+static void
+unlock_pool (void)
+{
+  int err;
+
+  pool_is_locked = 0;
+  err = gpgrt_lock_unlock (&pool_lock);
+  if (err)
+    log_fatal ("failed to release the pool lock: %s\n", gpg_strerror (err));
+}
+
+
+/* Full initialization of this module. */
+static void
+initialize(void)
+{
+  /* Although the basic initialization should have happened already,
+     we call it here to make sure that all prerequisites are met.  */
+  initialize_basics ();
+
+  /* Now we can look the pool and complete the initialization if
+     necessary.  */
+  lock_pool ();
+  if (!rndpool)
+    {
+      /* The data buffer is allocated somewhat larger, so that we can
+         use this extra space (which is allocated in secure memory) as
+         a temporary hash buffer */
+      rndpool = (secure_alloc
+                 ? xcalloc_secure (1, POOLSIZE + BLOCKLEN)
+                 : xcalloc (1, POOLSIZE + BLOCKLEN));
+      keypool = (secure_alloc
+                 ? xcalloc_secure (1, POOLSIZE + BLOCKLEN)
+                 : xcalloc (1, POOLSIZE + BLOCKLEN));
+
+      /* Setup the slow entropy gathering function.  The code requires
+         that this function exists. */
+      slow_gather_fnc = getfnc_gather_random ();
+
+      /* Setup the fast entropy gathering function.  */
+      fast_gather_fnc = getfnc_fast_random_poll ();
+
+    }
+  unlock_pool ();
+}
+
+
+
+
+/* Initialize this random subsystem.  If FULL is false, this function
+   merely calls the initialize and does not do anything more.  Doing
+   this is not really required but when running in a threaded
+   environment we might get a race condition otherwise. */
+void
+_gcry_rngcsprng_initialize (int full)
+{
+  if (!full)
+    initialize_basics ();
+  else
+    initialize ();
+}
+
+
+/* Try to close the FDs of the random gather module.  This is
+   currently only implemented for rndlinux. */
+void
+_gcry_rngcsprng_close_fds (void)
+{
+  lock_pool ();
+#if USE_RNDLINUX
+  _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
+  pool_filled = 0; /* Force re-open on next use.  */
+#endif
+  unlock_pool ();
+}
+
+
+void
+_gcry_rngcsprng_dump_stats (void)
+{
+  /* In theory we would need to lock the stats here.  However this
+     function is usually called during cleanup and then we _might_ run
+     into problems.  */
+
+  log_info ("random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
+	    "              outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu%s\n",
+            POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
+            rndstats.naddbytes, rndstats.addbytes,
+            rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
+            rndstats.ngetbytes2, rndstats.getbytes2,
+            _gcry_rndhw_failed_p()? " (hwrng failed)":"");
+}
+
+
+/* This function should be called during initialization and before
+   initialization of this module to place the random pools into secure
+   memory.  */
+void
+_gcry_rngcsprng_secure_alloc (void)
+{
+  secure_alloc = 1;
+}
+
+
+/* This may be called before full initialization to degrade the
+   quality of the RNG for the sake of a faster running test suite.  */
+void
+_gcry_rngcsprng_enable_quick_gen (void)
+{
+  quick_test = 1;
+}
+
+
+void
+_gcry_rngcsprng_set_daemon_socket (const char *socketname)
+{
+#ifdef USE_RANDOM_DAEMON
+  if (daemon_socket_name)
+    BUG ();
+
+  daemon_socket_name = gcry_xstrdup (socketname);
+#else /*!USE_RANDOM_DAEMON*/
+  (void)socketname;
+#endif /*!USE_RANDOM_DAEMON*/
+}
+
+/* With ONOFF set to 1, enable the use of the daemon.  With ONOFF set
+   to 0, disable the use of the daemon.  With ONOF set to -1, return
+   whether the daemon has been enabled. */
+int
+_gcry_rngcsprng_use_daemon (int onoff)
+{
+#ifdef USE_RANDOM_DAEMON
+  int last;
+
+  /* This is not really thread safe.  However it is expected that this
+     function is being called during initialization and at that point
+     we are for other reasons not really thread safe.  We do not want
+     to lock it because we might eventually decide that this function
+     may even be called prior to gcry_check_version.  */
+  last = allow_daemon;
+  if (onoff != -1)
+    allow_daemon = onoff;
+
+  return last;
+#else /*!USE_RANDOM_DAEMON*/
+  (void)onoff;
+  return 0;
+#endif /*!USE_RANDOM_DAEMON*/
+}
+
+
+/* This function returns true if no real RNG is available or the
+   quality of the RNG has been degraded for test purposes.  */
+int
+_gcry_rngcsprng_is_faked (void)
+{
+  /* We need to initialize due to the runtime determination of
+     available entropy gather modules.  */
+  initialize();
+  return quick_test;
+}
+
+
+/* Add BUFLEN bytes from BUF to the internal random pool.  QUALITY
+   should be in the range of 0..100 to indicate the goodness of the
+   entropy added, or -1 for goodness not known.  */
+gcry_error_t
+_gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, int quality)
+{
+  size_t nbytes;
+  const char *bufptr;
+
+  if (quality == -1)
+    quality = 35;
+  else if (quality > 100)
+    quality = 100;
+  else if (quality < 0)
+    quality = 0;
+
+  if (!buf)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  if (!buflen || quality < 10)
+    return 0; /* Take a shortcut. */
+
+  /* Because we don't increment the entropy estimation with FASTPOLL,
+     we don't need to take lock that estimation while adding from an
+     external source.  This limited entropy estimation also means that
+     we can't take QUALITY into account.  */
+  initialize_basics ();
+  bufptr = buf;
+  while (buflen)
+    {
+      nbytes = buflen > POOLSIZE? POOLSIZE : buflen;
+      lock_pool ();
+      if (rndpool)
+        add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL);
+      unlock_pool ();
+      bufptr += nbytes;
+      buflen -= nbytes;
+    }
+  return 0;
+}
+
+
+/* Public function to fill the buffer with LENGTH bytes of
+   cryptographically strong random bytes.  Level GCRY_WEAK_RANDOM is
+   not very strong, GCRY_STRONG_RANDOM is strong enough for most
+   usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but
+   may be very slow.  */
+void
+_gcry_rngcsprng_randomize (void *buffer, size_t length,
+                           enum gcry_random_level level)
+{
+  unsigned char *p;
+
+  /* Make sure we are initialized. */
+  initialize ();
+
+  /* Handle our hack used for regression tests of Libgcrypt. */
+  if ( quick_test && level > GCRY_STRONG_RANDOM )
+    level = GCRY_STRONG_RANDOM;
+
+  /* Make sure the level is okay. */
+  level &= 3;
+
+#ifdef USE_RANDOM_DAEMON
+  if (allow_daemon
+      && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level))
+    return; /* The daemon succeeded. */
+  allow_daemon = 0; /* Daemon failed - switch off. */
+#endif /*USE_RANDOM_DAEMON*/
+
+  /* Acquire the pool lock. */
+  lock_pool ();
+
+  /* Update the statistics. */
+  if (level >= GCRY_VERY_STRONG_RANDOM)
+    {
+      rndstats.getbytes2 += length;
+      rndstats.ngetbytes2++;
+    }
+  else
+    {
+      rndstats.getbytes1 += length;
+      rndstats.ngetbytes1++;
+    }
+
+  /* Read the random into the provided buffer. */
+  for (p = buffer; length > 0;)
+    {
+      size_t n;
+
+      n = length > POOLSIZE? POOLSIZE : length;
+      read_pool (p, n, level);
+      length -= n;
+      p += n;
+    }
+
+  /* Release the pool lock. */
+  unlock_pool ();
+}
+
+
+
+
+/*
+ * Mix the 600 byte pool.  Note that the 64 byte scratch area directly
+ * follows the pool.  The numbers in the diagram give the number of
+ * bytes.
+ *         <................600...............>   <.64.>
+ * pool   |------------------------------------| |------|
+ *         <20><.24.>                      <20>
+ *          |     |                         +-----+
+ *          +-----|-------------------------------|-+
+ *                +-------------------------------|-|-+
+ *                                                v v v
+ *                                               |------|
+ *                                                <hash>
+ *          +---------------------------------------+
+ *          v
+ *         <20>
+ * pool'  |------------------------------------|
+ *         <20><20><.24.>
+ *          +---|-----|---------------------------+
+ *              +-----|---------------------------|-+
+ *                    +---------------------------|-|-+
+ *                                                v v v
+ *                                               |------|
+ *                                                <hash>
+ *                                                  |
+ *              +-----------------------------------+
+ *              v
+ *             <20>
+ * pool'' |------------------------------------|
+ *         <20><20><20><.24.>
+ *              +---|-----|-----------------------+
+ *                  +-----|-----------------------|-+
+ *                        +-----------------------|-|-+
+ *                                                v v v
+ *
+ * and so on until we did this for all 30 blocks.
+ *
+ * To better protect against implementation errors in this code, we
+ * xor a digest of the entire pool into the pool before mixing.
+ *
+ * Note: this function must only be called with a locked pool.
+ */
+static void
+mix_pool(unsigned char *pool)
+{
+  static unsigned char failsafe_digest[DIGESTLEN];
+  static int failsafe_digest_valid;
+
+  unsigned char *hashbuf = pool + POOLSIZE;
+  unsigned char *p, *pend;
+  int i, n;
+  SHA1_CONTEXT md;
+  unsigned int nburn;
+
+#if DIGESTLEN != 20
+#error must have a digest length of 20 for SHA-1
+#endif
+
+  gcry_assert (pool_is_locked);
+  _gcry_sha1_mixblock_init (&md);
+
+  /* pool_0 -> pool'.  */
+  pend = pool + POOLSIZE;
+  memcpy (hashbuf, pend - DIGESTLEN, DIGESTLEN);
+  memcpy (hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+  nburn = _gcry_sha1_mixblock (&md, hashbuf);
+  memcpy (pool, hashbuf, DIGESTLEN);
+
+  if (failsafe_digest_valid && pool == rndpool)
+    {
+      for (i=0; i < DIGESTLEN; i++)
+        pool[i] ^= failsafe_digest[i];
+    }
+
+  /* Loop for the remaining iterations.  */
+  p = pool;
+  for (n=1; n < POOLBLOCKS; n++)
+    {
+      if (p + BLOCKLEN < pend)
+        memcpy (hashbuf, p, BLOCKLEN);
+      else
+        {
+          unsigned char *pp = p;
+
+          for (i=0; i < BLOCKLEN; i++ )
+            {
+              if ( pp >= pend )
+                pp = pool;
+              hashbuf[i] = *pp++;
+	    }
+	}
+
+      _gcry_sha1_mixblock (&md, hashbuf);
+      p += DIGESTLEN;
+      memcpy (p, hashbuf, DIGESTLEN);
+    }
+
+  /* Our hash implementation does only leave small parts (64 bytes)
+     of the pool on the stack, so it is okay not to require secure
+     memory here.  Before we use this pool, it will be copied to the
+     help buffer anyway. */
+  if ( pool == rndpool)
+    {
+      _gcry_sha1_hash_buffer (failsafe_digest, pool, POOLSIZE);
+      failsafe_digest_valid = 1;
+    }
+
+  _gcry_burn_stack (nburn);
+}
+
+
+void
+_gcry_rngcsprng_set_seed_file (const char *name)
+{
+  if (seed_file_name)
+    BUG ();
+  seed_file_name = xstrdup (name);
+}
+
+
+
+/* Helper for my_open.
+ * Return a malloced wide char string from an UTF-8 encoded input
+ * string STRING.  Caller must free this value.  Returns NULL and sets
+ * ERRNO on failure.  Calling this function with STRING set to NULL is
+ * not defined.  */
+#ifdef HAVE_W32_SYSTEM
+static wchar_t *
+utf8_to_wchar (const char *string)
+{
+  int n;
+  size_t nbytes;
+  wchar_t *result;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
+  if (n < 0)
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  nbytes = (size_t)(n+1) * sizeof(*result);
+  if (nbytes / sizeof(*result) != (n+1))
+    {
+      gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+  result = xtrymalloc (nbytes);
+  if (!result)
+    return NULL;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
+  if (n < 0)
+    {
+      xfree (result);
+      gpg_err_set_errno (EINVAL);
+      result = NULL;
+    }
+  return result;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Helper for my_open.  */
+#ifdef HAVE_W32_SYSTEM
+static int
+any8bitchar (const char *string)
+{
+  if (string)
+    for ( ; *string; string++)
+      if ((*string & 0x80))
+        return 1;
+  return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* A wrapper around open to handle Unicode file names under Windows.  */
+static int
+my_open (const char *name, int flags, unsigned int mode)
+{
+#ifdef HAVE_W32_SYSTEM
+  if (any8bitchar (name))
+    {
+      wchar_t *wname;
+      int ret;
+
+      wname = utf8_to_wchar (name);
+      if (!wname)
+        return -1;
+      ret = _wopen (wname, flags, mode);
+      xfree (wname);
+      return ret;
+    }
+  else
+    return open (name, flags, mode);
+#else
+  return open (name, flags, mode);
+#endif
+}
+
+
+/* Lock an open file identified by file descriptor FD and wait a
+   reasonable time to succeed.  With FOR_WRITE set to true a write
+   lock will be taken.  FNAME is used only for diagnostics. Returns 0
+   on success or -1 on error. */
+static int
+lock_seed_file (int fd, const char *fname, int for_write)
+{
+#ifdef __GCC__
+#warning Check whether we can lock on Windows.
+#endif
+#if LOCK_SEED_FILE
+  struct flock lck;
+  struct timeval tv;
+  int backoff=0;
+
+  /* We take a lock on the entire file. */
+  memset (&lck, 0, sizeof lck);
+  lck.l_type = for_write? F_WRLCK : F_RDLCK;
+  lck.l_whence = SEEK_SET;
+
+  while (fcntl (fd, F_SETLK, &lck) == -1)
+    {
+      if (errno != EAGAIN && errno != EACCES)
+        {
+          log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
+          return -1;
+        }
+
+      if (backoff > 2) /* Show the first message after ~2.25 seconds. */
+        log_info( _("waiting for lock on `%s'...\n"), fname);
+
+      tv.tv_sec = backoff;
+      tv.tv_usec = 250000;
+      select (0, NULL, NULL, NULL, &tv);
+      if (backoff < 10)
+        backoff++ ;
+    }
+#endif /*!LOCK_SEED_FILE*/
+  return 0;
+}
+
+
+/* Read in a seed from the random_seed file and return true if this
+   was successful.
+
+   Note: Multiple instances of applications sharing the same random
+   seed file can be started in parallel, in which case they will read
+   out the same pool and then race for updating it (the last update
+   overwrites earlier updates).  They will differentiate only by the
+   weak entropy that is added in read_seed_file based on the PID and
+   clock, and up to 32 bytes from a non-blocking entropy source.  The
+   consequence is that the output of these different instances is
+   correlated to some extent.  In the perfect scenario, the attacker
+   can control (or at least guess) the PID and clock of the
+   application, and drain the system's entropy pool to reduce the "up
+   to 32 bytes" above to 0.  Then the dependencies of the initial
+   states of the pools are completely known.  */
+static int
+read_seed_file (void)
+{
+  int fd;
+  struct stat sb;
+  unsigned char buffer[POOLSIZE];
+  int n;
+
+  gcry_assert (pool_is_locked);
+
+  if (!seed_file_name)
+    return 0;
+
+#ifdef HAVE_DOSISH_SYSTEM
+  fd = my_open (seed_file_name, O_RDONLY | O_BINARY, 0);
+#else
+  fd = my_open (seed_file_name, O_RDONLY, 0);
+#endif
+  if( fd == -1 && errno == ENOENT)
+    {
+      allow_seed_file_update = 1;
+      return 0;
+    }
+
+  if (fd == -1 )
+    {
+      log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+      return 0;
+    }
+  if (lock_seed_file (fd, seed_file_name, 0))
+    {
+      close (fd);
+      return 0;
+    }
+  if (fstat( fd, &sb ) )
+    {
+      log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+      close(fd);
+      return 0;
+    }
+  if (!S_ISREG(sb.st_mode) )
+    {
+      log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+      close(fd);
+      return 0;
+    }
+  if (!sb.st_size )
+    {
+      log_info(_("note: random_seed file is empty\n") );
+      close(fd);
+      allow_seed_file_update = 1;
+      return 0;
+    }
+  if (sb.st_size != POOLSIZE )
+    {
+      log_info(_("warning: invalid size of random_seed file - not used\n") );
+      close(fd);
+      return 0;
+    }
+
+  do
+    {
+      n = read( fd, buffer, POOLSIZE );
+    }
+  while (n == -1 && errno == EINTR );
+
+  if (n != POOLSIZE)
+    {
+      log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+      close(fd);/*NOTREACHED*/
+      return 0;
+    }
+
+  close(fd);
+
+  add_randomness( buffer, POOLSIZE, RANDOM_ORIGIN_INIT );
+  /* add some minor entropy to the pool now (this will also force a mixing) */
+  {
+    pid_t x = getpid();
+    add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+  }
+  {
+    time_t x = time(NULL);
+    add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+  }
+  {
+    clock_t x = clock();
+    add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+  }
+
+  /* And read a few bytes from our entropy source.  If we have the
+   * Jitter RNG we can fast get a lot of entropy.  Thus we read 1024
+   * bits from that source.
+   *
+   * Without the Jitter RNG we keep the old method of reading only a
+   * few bytes usually from /dev/urandom which won't block.  */
+  if (_gcry_rndjent_get_version (NULL))
+    read_random_source (RANDOM_ORIGIN_INIT, 128, GCRY_STRONG_RANDOM);
+  else
+    read_random_source (RANDOM_ORIGIN_INIT, 32, GCRY_STRONG_RANDOM);
+
+  allow_seed_file_update = 1;
+  return 1;
+}
+
+
+void
+_gcry_rngcsprng_update_seed_file (void)
+{
+  unsigned long *sp, *dp;
+  int fd, i;
+
+  /* We do only a basic initialization so that we can lock the pool.
+     This is required to cope with the case that this function is
+     called by some cleanup code at a point where the RNG has never
+     been initialized.  */
+  initialize_basics ();
+  lock_pool ();
+
+  if ( !seed_file_name || !rndpool || !pool_filled )
+    {
+      unlock_pool ();
+      return;
+    }
+  if ( !allow_seed_file_update )
+    {
+      unlock_pool ();
+      log_info(_("note: random_seed file not updated\n"));
+      return;
+    }
+
+  /* At this point we know that there is something in the pool and
+     thus we can conclude that the pool has been fully initialized.  */
+
+
+  /* Copy the entropy pool to a scratch pool and mix both of them. */
+  for (i=0,dp=(unsigned long*)(void*)keypool, sp=(unsigned long*)(void*)rndpool;
+       i < POOLWORDS; i++, dp++, sp++ )
+    {
+      *dp = *sp + ADD_VALUE;
+    }
+  mix_pool(rndpool); rndstats.mixrnd++;
+  mix_pool(keypool); rndstats.mixkey++;
+
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
+  fd = my_open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+                S_IRUSR|S_IWUSR );
+#else
+# if LOCK_SEED_FILE
+    fd = my_open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
+# else
+    fd = my_open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# endif
+#endif
+
+  if (fd == -1 )
+    log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+  else if (lock_seed_file (fd, seed_file_name, 1))
+    {
+      close (fd);
+    }
+#if LOCK_SEED_FILE
+  else if (ftruncate (fd, 0))
+    {
+      log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
+      close (fd);
+    }
+#endif /*LOCK_SEED_FILE*/
+  else
+    {
+      do
+        {
+          i = write (fd, keypool, POOLSIZE );
+        }
+      while (i == -1 && errno == EINTR);
+      if (i != POOLSIZE)
+        log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
+      if (close(fd))
+        log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
+    }
+
+  unlock_pool ();
+}
+
+
+/* Read random out of the pool.  This function is the core of the
+   public random functions.  Note that Level GCRY_WEAK_RANDOM is not
+   anymore handled special and in fact is an alias in the API for
+   level GCRY_STRONG_RANDOM.  Must be called with the pool already
+   locked.  */
+static void
+read_pool (byte *buffer, size_t length, int level)
+{
+  int i;
+  unsigned long *sp, *dp;
+  /* The volatile is there to make sure the compiler does not optimize
+     the code away in case the getpid function is badly attributed.
+     Note that we keep a pid in a static variable as well as in a
+     stack based one; the latter is to detect ill behaving thread
+     libraries, ignoring the pool mutexes. */
+  static volatile pid_t my_pid = (pid_t)(-1);
+  volatile pid_t my_pid2;
+
+  gcry_assert (pool_is_locked);
+
+ retry:
+  /* Get our own pid, so that we can detect a fork. */
+  my_pid2 = getpid ();
+  if (my_pid == (pid_t)(-1))
+    my_pid = my_pid2;
+  if ( my_pid != my_pid2 )
+    {
+      /* We detected a plain fork; i.e. we are now the child.  Update
+         the static pid and add some randomness. */
+      pid_t x;
+
+      my_pid = my_pid2;
+      x = my_pid;
+      add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
+      just_mixed = 0; /* Make sure it will get mixed. */
+    }
+
+  gcry_assert (pool_is_locked);
+
+  /* Our code does not allow to extract more than POOLSIZE.  Better
+     check it here. */
+  if (length > POOLSIZE)
+    {
+      log_bug("too many random bits requested\n");
+    }
+
+  if (!pool_filled)
+    {
+      if (read_seed_file() )
+        pool_filled = 1;
+    }
+
+  /* For level 2 quality (key generation) we always make sure that the
+     pool has been seeded enough initially. */
+  if (level == GCRY_VERY_STRONG_RANDOM && !did_initial_extra_seeding)
+    {
+      size_t needed;
+
+      pool_balance = 0;
+      needed = length - pool_balance;
+      if (needed < 16)  /* At least 128 bits.  */
+        needed = 16;
+      else if( needed > POOLSIZE )
+        BUG ();
+      read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
+                          GCRY_VERY_STRONG_RANDOM);
+      pool_balance += needed;
+      did_initial_extra_seeding = 1;
+    }
+
+  /* For level 2 make sure that there is enough random in the pool. */
+  if (level == GCRY_VERY_STRONG_RANDOM && pool_balance < length)
+    {
+      size_t needed;
+
+      if (pool_balance < 0)
+        pool_balance = 0;
+      needed = length - pool_balance;
+      if (needed > POOLSIZE)
+        BUG ();
+      read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
+                          GCRY_VERY_STRONG_RANDOM);
+      pool_balance += needed;
+    }
+
+  /* Make sure the pool is filled. */
+  while (!pool_filled)
+    random_poll();
+
+  /* Always do a fast random poll (we have to use the unlocked version). */
+  do_fast_random_poll();
+
+  /* Mix the pid in so that we for sure won't deliver the same random
+     after a fork. */
+  {
+    pid_t apid = my_pid;
+    add_randomness (&apid, sizeof (apid), RANDOM_ORIGIN_INIT);
+  }
+
+  /* Mix the pool (if add_randomness() didn't it). */
+  if (!just_mixed)
+    {
+      mix_pool(rndpool);
+      rndstats.mixrnd++;
+    }
+
+  /* Create a new pool. */
+  for(i=0,dp=(unsigned long*)(void*)keypool, sp=(unsigned long*)(void*)rndpool;
+      i < POOLWORDS; i++, dp++, sp++ )
+    *dp = *sp + ADD_VALUE;
+
+  /* Mix both pools. */
+  mix_pool(rndpool); rndstats.mixrnd++;
+  mix_pool(keypool); rndstats.mixkey++;
+
+  /* Read the requested data.  We use a read pointer to read from a
+     different position each time.  */
+  while (length--)
+    {
+      *buffer++ = keypool[pool_readpos++];
+      if (pool_readpos >= POOLSIZE)
+        pool_readpos = 0;
+      pool_balance--;
+    }
+
+  if (pool_balance < 0)
+    pool_balance = 0;
+
+  /* Clear the keypool. */
+  memset (keypool, 0, POOLSIZE);
+
+  /* We need to detect whether a fork has happened.  A fork might have
+     an identical pool and thus the child and the parent could emit
+     the very same random number.  This test here is to detect forks
+     in a multi-threaded process.  It does not work with all thread
+     implementations in particular not with pthreads.  However it is
+     good enough for GNU Pth. */
+  if ( getpid () != my_pid2 )
+    {
+      pid_t x = getpid();
+      add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
+      just_mixed = 0; /* Make sure it will get mixed. */
+      my_pid = x;     /* Also update the static pid. */
+      goto retry;
+    }
+}
+
+
+
+/* Add LENGTH bytes of randomness from buffer to the pool.  ORIGIN is
+   used to specify the randomness origin.  This is one of the
+   RANDOM_ORIGIN_* values. */
+static void
+add_randomness (const void *buffer, size_t length, enum random_origins origin)
+{
+  const unsigned char *p = buffer;
+  size_t count = 0;
+
+  gcry_assert (pool_is_locked);
+
+  rndstats.addbytes += length;
+  rndstats.naddbytes++;
+  while (length-- )
+    {
+      rndpool[pool_writepos++] ^= *p++;
+      count++;
+      if (pool_writepos >= POOLSIZE )
+        {
+          /* It is possible that we are invoked before the pool is
+             filled using an unreliable origin of entropy, for example
+             the fast random poll.  To avoid flagging the pool as
+             filled in this case, we track the initial filling state
+             separately.  See also the remarks about the seed file. */
+          if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled)
+            {
+              pool_filled_counter += count;
+              count = 0;
+              if (pool_filled_counter >= POOLSIZE)
+                pool_filled = 1;
+            }
+          pool_writepos = 0;
+          mix_pool(rndpool); rndstats.mixrnd++;
+          just_mixed = !length;
+	}
+    }
+}
+
+
+
+static void
+random_poll()
+{
+  rndstats.slowpolls++;
+  read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM);
+}
+
+
+/* Runtime determination of the slow entropy gathering module.  */
+static int (*
+getfnc_gather_random (void))(void (*)(const void*, size_t,
+                                      enum random_origins),
+                             enum random_origins, size_t, int)
+{
+  int (*fnc)(void (*)(const void*, size_t, enum random_origins),
+             enum random_origins, size_t, int);
+
+#if USE_RNDLINUX
+  if ( !access (NAME_OF_DEV_RANDOM, R_OK)
+       && !access (NAME_OF_DEV_URANDOM, R_OK))
+    {
+      fnc = _gcry_rndlinux_gather_random;
+      return fnc;
+    }
+#endif
+
+#if USE_RNDEGD
+  if ( _gcry_rndegd_connect_socket (1) != -1 )
+    {
+      fnc = _gcry_rndegd_gather_random;
+      return fnc;
+    }
+#endif
+
+#if USE_RNDUNIX
+  fnc = _gcry_rndunix_gather_random;
+  return fnc;
+#endif
+
+#if USE_RNDW32
+  fnc = _gcry_rndw32_gather_random;
+  return fnc;
+#endif
+
+#if USE_RNDW32CE
+  fnc = _gcry_rndw32ce_gather_random;
+  return fnc;
+#endif
+
+  log_fatal (_("no entropy gathering module detected\n"));
+
+  return NULL; /*NOTREACHED*/
+}
+
+/* Runtime determination of the fast entropy gathering function.
+   (Currently a compile time method is used.)  */
+static void (*
+getfnc_fast_random_poll (void))( void (*)(const void*, size_t,
+                                          enum random_origins),
+                                 enum random_origins)
+{
+#if USE_RNDW32
+  return _gcry_rndw32_gather_random_fast;
+#endif
+#if USE_RNDW32CE
+  return _gcry_rndw32ce_gather_random_fast;
+#endif
+  return NULL;
+}
+
+
+
+static void
+do_fast_random_poll (void)
+{
+  gcry_assert (pool_is_locked);
+
+  rndstats.fastpolls++;
+
+  if (fast_gather_fnc)
+    fast_gather_fnc (add_randomness, RANDOM_ORIGIN_FASTPOLL);
+
+  /* Continue with the generic functions. */
+#if HAVE_GETHRTIME
+  {
+    hrtime_t tv;
+    tv = gethrtime();
+    add_randomness( &tv, sizeof(tv), RANDOM_ORIGIN_FASTPOLL );
+  }
+#elif HAVE_GETTIMEOFDAY
+  {
+    struct timeval tv;
+    if( gettimeofday( &tv, NULL ) )
+      BUG();
+    add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
+    add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), RANDOM_ORIGIN_FASTPOLL );
+  }
+#elif HAVE_CLOCK_GETTIME
+  {	struct timespec tv;
+  if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+    BUG();
+  add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
+  add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), RANDOM_ORIGIN_FASTPOLL );
+  }
+#else /* use times */
+# ifndef HAVE_DOSISH_SYSTEM
+  {	struct tms buf;
+  times( &buf );
+  add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
+  }
+# endif
+#endif
+
+#ifdef HAVE_GETRUSAGE
+# ifdef RUSAGE_SELF
+  {
+    struct rusage buf;
+    /* QNX/Neutrino does return ENOSYS - so we just ignore it and add
+       whatever is in buf.  In a chroot environment it might not work
+       at all (i.e. because /proc/ is not accessible), so we better
+       ignore all error codes and hope for the best. */
+    getrusage (RUSAGE_SELF, &buf );
+    add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
+    memset( &buf, 0, sizeof buf );
+  }
+# else /*!RUSAGE_SELF*/
+#  ifdef __GCC__
+#   warning There is no RUSAGE_SELF on this system
+#  endif
+# endif /*!RUSAGE_SELF*/
+#endif /*HAVE_GETRUSAGE*/
+
+  /* Time and clock are available on all systems - so we better do it
+     just in case one of the above functions didn't work.  */
+  {
+    time_t x = time(NULL);
+    add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
+  }
+  {
+    clock_t x = clock();
+    add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
+  }
+
+  /* If the system features a fast hardware RNG, read some bytes from
+     there.  */
+  _gcry_rndhw_poll_fast (add_randomness, RANDOM_ORIGIN_FASTPOLL);
+}
+
+
+/* The fast random pool function as called at some places in
+   libgcrypt.  This is merely a wrapper to make sure that this module
+   is initialized and to lock the pool.  Note, that this function is a
+   NOP unless a random function has been used or _gcry_initialize (1)
+   has been used.  We use this hack so that the internal use of this
+   function in cipher_open and md_open won't start filling up the
+   random pool, even if no random will be required by the process. */
+void
+_gcry_rngcsprng_fast_poll (void)
+{
+  initialize_basics ();
+
+  lock_pool ();
+  if (rndpool)
+    {
+      /* Yes, we are fully initialized. */
+      do_fast_random_poll ();
+    }
+  unlock_pool ();
+}
+
+
+
+static void
+read_random_source (enum random_origins origin, size_t length, int level)
+{
+  if ( !slow_gather_fnc )
+    log_fatal ("Slow entropy gathering module not yet initialized\n");
+
+  if (slow_gather_fnc (add_randomness, origin, length, level) < 0)
+    log_fatal ("No way to gather entropy for the RNG\n");
+}