diff options
Diffstat (limited to 'libgcrypt-1.4.6/random/random-csprng.c')
-rw-r--r-- | libgcrypt-1.4.6/random/random-csprng.c | 2805 |
1 files changed, 1397 insertions, 1408 deletions
diff --git a/libgcrypt-1.4.6/random/random-csprng.c b/libgcrypt-1.4.6/random/random-csprng.c index ea446ac..aca977e 100644 --- a/libgcrypt-1.4.6/random/random-csprng.c +++ b/libgcrypt-1.4.6/random/random-csprng.c @@ -1,1408 +1,1397 @@ -/* random-csprng.c - CSPRNG style random number generator (libgcrypt classic)
- * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2010 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 "../cipher/rmd.h"
-#include "random.h"
-#include "rand-internal.h"
-#include "cipher.h" /* Required for the rmd160_hash_buffer() prototype. */
-#include "ath.h"
-
-#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 (rmd160). */
-/* 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 rereading 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 regsitered 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 initailization. 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;
-
-/* On systems without entropy gathering modules, this flag is set to
- indicate that the random generator is not working properly. A
- warning message is issued as well. This is useful only for
- debugging and during development. */
-static int faked_rng;
-
-/* This is the lock we use to protect all pool operations. */
-static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER;
-
-/* 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;
-
-/* This is the lock we use to protect the buffer used by the nonce
- generation. */
-static ath_mutex_t nonce_buffer_lock = ATH_MUTEX_INITIALIZER;
-
-
-/* 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);
-static int gather_faked (void (*add)(const void*, size_t, enum random_origins),
- enum random_origins, 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;
- int err;
-
- if (!initialized)
- {
- initialized = 1;
- err = ath_mutex_init (&pool_lock);
- if (err)
- log_fatal ("failed to create the pool lock: %s\n", strerror (err) );
-
- err = ath_mutex_init (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to create the nonce buffer lock: %s\n",
- strerror (err) );
-
-#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 = ath_mutex_lock (&pool_lock);
- if (err)
- log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
- pool_is_locked = 1;
-}
-
-/* Release the pool lock. */
-static void
-unlock_pool (void)
-{
- int err;
-
- pool_is_locked = 0;
- err = ath_mutex_unlock (&pool_lock);
- if (err)
- log_fatal ("failed to release the pool lock: %s\n", 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
- ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
- : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
- keypool = (secure_alloc
- ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
- : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
-
- /* Setup the slow entropy gathering function. The code requires
- that this function exists. */
- slow_gather_fnc = getfnc_gather_random ();
- if (!slow_gather_fnc)
- {
- faked_rng = 1;
- slow_gather_fnc = gather_faked;
- }
-
- /* 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 ();
-}
-
-
-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 (faked_rng || 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 pool:
-
- |........blocks*20byte........|20byte|..44byte..|
- <..44byte..> <20byte>
- | |
- | +------+
- +---------------------------|----------+
- v v
- |........blocks*20byte........|20byte|..44byte..|
- <.....64bytes.....>
- |
- +----------------------------------+
- Hash
- v
- |.............................|20byte|..44byte..|
- <20byte><20byte><..44byte..>
- | |
- | +---------------------+
- +-----------------------------+ |
- v v
- |.............................|20byte|..44byte..|
- <.....64byte......>
- |
- +-------------------------+
- Hash
- v
- |.............................|20byte|..44byte..|
- <20byte><20byte><..44byte..>
-
- and so on until we did this for all 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;
- RMD160_CONTEXT md;
-
-#if DIGESTLEN != 20
-#error must have a digest length of 20 for ripe-md-160
-#endif
-
- gcry_assert (pool_is_locked);
- _gcry_rmd160_init( &md );
-
- /* Loop over the pool. */
- pend = pool + POOLSIZE;
- memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
- memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
- _gcry_rmd160_mixblock( &md, hashbuf);
- memcpy(pool, hashbuf, 20 );
-
- if (failsafe_digest_valid && pool == rndpool)
- {
- for (i=0; i < 20; i++)
- pool[i] ^= failsafe_digest[i];
- }
-
- p = pool;
- for (n=1; n < POOLBLOCKS; n++)
- {
- memcpy (hashbuf, p, DIGESTLEN);
-
- p += DIGESTLEN;
- if (p+DIGESTLEN+BLOCKLEN < pend)
- memcpy (hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
- else
- {
- unsigned char *pp = p + DIGESTLEN;
-
- for (i=DIGESTLEN; i < BLOCKLEN; i++ )
- {
- if ( pp >= pend )
- pp = pool;
- hashbuf[i] = *pp++;
- }
- }
-
- _gcry_rmd160_mixblock ( &md, hashbuf);
- memcpy(p, hashbuf, 20 );
- }
-
- /* 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_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE);
- failsafe_digest_valid = 1;
- }
-
- _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
-}
-
-
-void
-_gcry_rngcsprng_set_seed_file (const char *name)
-{
- if (seed_file_name)
- BUG ();
- seed_file_name = gcry_xstrdup (name);
-}
-
-
-/* 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 16 bytes of weak random non-blockingly. 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 16 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 = _open( seed_file_name, O_RDONLY | O_BINARY );
-#else
- fd = open( seed_file_name, O_RDONLY );
-#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. By using a level
- * of 0 this will not block and might not return anything with some
- * entropy drivers, however the rndlinux driver will use
- * /dev/urandom and return some stuff - Do not read too much as we
- * want to be friendly to the scare system entropy resource. */
- read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_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*)keypool, sp=(unsigned long*)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 = _open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
- S_IRUSR|S_IWUSR );
-#else
-# if LOCK_SEED_FILE
- fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
-# else
- fd = 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 < POOLSIZE/2)
- needed = POOLSIZE/2;
- 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*)keypool, sp=(unsigned long*)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 availabe 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 orgin, 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, orgin, length, level) < 0)
- log_fatal ("No way to gather entropy for the RNG\n");
-}
-
-
-static int
-gather_faked (void (*add)(const void*, size_t, enum random_origins),
- enum random_origins origin, size_t length, int level )
-{
- static int initialized=0;
- size_t n;
- char *buffer, *p;
-
- (void)add;
- (void)level;
-
- if ( !initialized )
- {
- log_info(_("WARNING: using insecure random number generator!!\n"));
- initialized=1;
-#ifdef HAVE_RAND
- srand( time(NULL)*getpid());
-#else
- srandom( time(NULL)*getpid());
-#endif
- }
-
- p = buffer = gcry_xmalloc( length );
- n = length;
-#ifdef HAVE_RAND
- while ( n-- )
- *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
-#else
- while ( n-- )
- *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
-#endif
- add_randomness ( buffer, length, origin );
- gcry_free (buffer);
- return 0; /* okay */
-}
-
-
-/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
-void
-_gcry_rngcsprng_create_nonce (void *buffer, size_t length)
-{
- static unsigned char nonce_buffer[20+8];
- static int nonce_buffer_initialized = 0;
- static volatile pid_t my_pid; /* The volatile is there to make sure the
- compiler does not optimize the code away
- in case the getpid function is badly
- attributed. */
- volatile pid_t apid;
- unsigned char *p;
- size_t n;
- int err;
-
- /* Make sure we are initialized. */
- initialize ();
-
-#ifdef USE_RANDOM_DAEMON
- if (allow_daemon
- && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length))
- return; /* The daemon succeeded. */
- allow_daemon = 0; /* Daemon failed - switch off. */
-#endif /*USE_RANDOM_DAEMON*/
-
- /* Acquire the nonce buffer lock. */
- err = ath_mutex_lock (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to acquire the nonce buffer lock: %s\n",
- strerror (err));
-
- apid = getpid ();
- /* The first time initialize our buffer. */
- if (!nonce_buffer_initialized)
- {
- time_t atime = time (NULL);
- pid_t xpid = apid;
-
- my_pid = apid;
-
- if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
- BUG ();
-
- /* Initialize the first 20 bytes with a reasonable value so that
- a failure of gcry_randomize won't affect us too much. Don't
- care about the uninitialized remaining bytes. */
- p = nonce_buffer;
- memcpy (p, &xpid, sizeof xpid);
- p += sizeof xpid;
- memcpy (p, &atime, sizeof atime);
-
- /* Initialize the never changing private part of 64 bits. */
- gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
-
- nonce_buffer_initialized = 1;
- }
- else if ( my_pid != apid )
- {
- /* We forked. Need to reseed the buffer - doing this for the
- private part should be sufficient. */
- gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
- /* Update the pid so that we won't run into here again and
- again. */
- my_pid = apid;
- }
-
- /* Create the nonce by hashing the entire buffer, returning the hash
- and updating the first 20 bytes of the buffer with this hash. */
- for (p = buffer; length > 0; length -= n, p += n)
- {
- _gcry_sha1_hash_buffer (nonce_buffer,
- nonce_buffer, sizeof nonce_buffer);
- n = length > 20? 20 : length;
- memcpy (p, nonce_buffer, n);
- }
-
-
- /* Release the nonce buffer lock. */
- err = ath_mutex_unlock (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to release the nonce buffer lock: %s\n",
- strerror (err));
-
-}
+/* random-csprng.c - CSPRNG style random number generator (libgcrypt classic) + * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + * 2007, 2008 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 "../cipher/rmd.h" +#include "random.h" +#include "rand-internal.h" +#include "cipher.h" /* Required for the rmd160_hash_buffer() prototype. */ +#include "ath.h" + +#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 (rmd160). */ +/* 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 rereading 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 + otehr 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 regsitered 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 initailization. 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 fucntion + 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; + +/* On systems without entropy gathering modules, this flag is set to + indicate that the random generator is not working properly. A + warning message is issued as well. This is useful only for + debugging and during development. */ +static int faked_rng; + +/* This is the lock we use to protect all pool operations. */ +static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER; + +/* 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; + +/* This is the lock we use to protect the buffer used by the nonce + generation. */ +static ath_mutex_t nonce_buffer_lock = ATH_MUTEX_INITIALIZER; + + +/* 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); +static int gather_faked (void (*add)(const void*, size_t, enum random_origins), + enum random_origins, 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; + int err; + + if (!initialized) + { + initialized = 1; + err = ath_mutex_init (&pool_lock); + if (err) + log_fatal ("failed to create the pool lock: %s\n", strerror (err) ); + + err = ath_mutex_init (&nonce_buffer_lock); + if (err) + log_fatal ("failed to create the nonce buffer lock: %s\n", + strerror (err) ); + +#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 = ath_mutex_lock (&pool_lock); + if (err) + log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); + pool_is_locked = 1; +} + +/* Release the pool lock. */ +static void +unlock_pool (void) +{ + int err; + + pool_is_locked = 0; + err = ath_mutex_unlock (&pool_lock); + if (err) + log_fatal ("failed to release the pool lock: %s\n", 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 + ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : gcry_xcalloc (1, POOLSIZE + BLOCKLEN)); + keypool = (secure_alloc + ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : gcry_xcalloc (1, POOLSIZE + BLOCKLEN)); + + /* Setup the slow entropy gathering function. The code requires + that this function exists. */ + slow_gather_fnc = getfnc_gather_random (); + if (!slow_gather_fnc) + { + faked_rng = 1; + slow_gather_fnc = gather_faked; + } + + /* 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 (); +} + + +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 + intialization 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 (faked_rng || 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 pool: + + |........blocks*20byte........|20byte|..44byte..| + <..44byte..> <20byte> + | | + | +------+ + +---------------------------|----------+ + v v + |........blocks*20byte........|20byte|..44byte..| + <.....64bytes.....> + | + +----------------------------------+ + Hash + v + |.............................|20byte|..44byte..| + <20byte><20byte><..44byte..> + | | + | +---------------------+ + +-----------------------------+ | + v v + |.............................|20byte|..44byte..| + <.....64byte......> + | + +-------------------------+ + Hash + v + |.............................|20byte|..44byte..| + <20byte><20byte><..44byte..> + + and so on until we did this for all 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; + RMD160_CONTEXT md; + +#if DIGESTLEN != 20 +#error must have a digest length of 20 for ripe-md-160 +#endif + + gcry_assert (pool_is_locked); + _gcry_rmd160_init( &md ); + + /* Loop over the pool. */ + pend = pool + POOLSIZE; + memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN ); + memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN); + _gcry_rmd160_mixblock( &md, hashbuf); + memcpy(pool, hashbuf, 20 ); + + if (failsafe_digest_valid && pool == rndpool) + { + for (i=0; i < 20; i++) + pool[i] ^= failsafe_digest[i]; + } + + p = pool; + for (n=1; n < POOLBLOCKS; n++) + { + memcpy (hashbuf, p, DIGESTLEN); + + p += DIGESTLEN; + if (p+DIGESTLEN+BLOCKLEN < pend) + memcpy (hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN); + else + { + unsigned char *pp = p + DIGESTLEN; + + for (i=DIGESTLEN; i < BLOCKLEN; i++ ) + { + if ( pp >= pend ) + pp = pool; + hashbuf[i] = *pp++; + } + } + + _gcry_rmd160_mixblock ( &md, hashbuf); + memcpy(p, hashbuf, 20 ); + } + + /* 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_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE); + failsafe_digest_valid = 1; + } + + _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */ +} + + +void +_gcry_rngcsprng_set_seed_file (const char *name) +{ + if (seed_file_name) + BUG (); + seed_file_name = gcry_xstrdup (name); +} + + +/* 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) +{ +#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 16 bytes of weak random non-blockingly. 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 16 bytes" above to 0. Then the dependencies of the inital + 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 = open( seed_file_name, O_RDONLY | O_BINARY ); +#else + fd = open( seed_file_name, O_RDONLY ); +#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. By using a level + * of 0 this will not block and might not return anything with some + * entropy drivers, however the rndlinux driver will use + * /dev/urandom and return some stuff - Do not read too much as we + * want to be friendly to the scare system entropy resource. */ + read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_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*)keypool, sp=(unsigned long*)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 = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, + S_IRUSR|S_IWUSR ); +#else +# if LOCK_SEED_FILE + fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); +# else + fd = 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 < POOLSIZE/2) + needed = POOLSIZE/2; + 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*)keypool, sp=(unsigned long*)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 + + 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 + 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 availabe 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 initalized and to look 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 orgin, 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, orgin, length, level) < 0) + log_fatal ("No way to gather entropy for the RNG\n"); +} + + +static int +gather_faked (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, size_t length, int level ) +{ + static int initialized=0; + size_t n; + char *buffer, *p; + + (void)add; + (void)level; + + if ( !initialized ) + { + log_info(_("WARNING: using insecure random number generator!!\n")); + initialized=1; +#ifdef HAVE_RAND + srand( time(NULL)*getpid()); +#else + srandom( time(NULL)*getpid()); +#endif + } + + p = buffer = gcry_xmalloc( length ); + n = length; +#ifdef HAVE_RAND + while ( n-- ) + *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1); +#else + while ( n-- ) + *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1); +#endif + add_randomness ( buffer, length, origin ); + gcry_free (buffer); + return 0; /* okay */ +} + + +/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ +void +_gcry_rngcsprng_create_nonce (void *buffer, size_t length) +{ + static unsigned char nonce_buffer[20+8]; + static int nonce_buffer_initialized = 0; + static volatile pid_t my_pid; /* The volatile is there to make sure the + compiler does not optimize the code away + in case the getpid function is badly + attributed. */ + volatile pid_t apid; + unsigned char *p; + size_t n; + int err; + + /* Make sure we are initialized. */ + initialize (); + +#ifdef USE_RANDOM_DAEMON + if (allow_daemon + && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length)) + return; /* The daemon succeeded. */ + allow_daemon = 0; /* Daemon failed - switch off. */ +#endif /*USE_RANDOM_DAEMON*/ + + /* Acquire the nonce buffer lock. */ + err = ath_mutex_lock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to acquire the nonce buffer lock: %s\n", + strerror (err)); + + apid = getpid (); + /* The first time intialize our buffer. */ + if (!nonce_buffer_initialized) + { + time_t atime = time (NULL); + pid_t xpid = apid; + + my_pid = apid; + + if ((sizeof apid + sizeof atime) > sizeof nonce_buffer) + BUG (); + + /* Initialize the first 20 bytes with a reasonable value so that + a failure of gcry_randomize won't affect us too much. Don't + care about the uninitialized remaining bytes. */ + p = nonce_buffer; + memcpy (p, &xpid, sizeof xpid); + p += sizeof xpid; + memcpy (p, &atime, sizeof atime); + + /* Initialize the never changing private part of 64 bits. */ + gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + + nonce_buffer_initialized = 1; + } + else if ( my_pid != apid ) + { + /* We forked. Need to reseed the buffer - doing this for the + private part should be sufficient. */ + gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + /* Update the pid so that we won't run into here again and + again. */ + my_pid = apid; + } + + /* Create the nonce by hashing the entire buffer, returning the hash + and updating the first 20 bytes of the buffer with this hash. */ + for (p = buffer; length > 0; length -= n, p += n) + { + _gcry_sha1_hash_buffer (nonce_buffer, + nonce_buffer, sizeof nonce_buffer); + n = length > 20? 20 : length; + memcpy (p, nonce_buffer, n); + } + + + /* Release the nonce buffer lock. */ + err = ath_mutex_unlock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to release the nonce buffer lock: %s\n", + strerror (err)); + +} |