Commit message: random: Hash continuous areas in the csprng pool.

* random/random-csprng.c (mix_pool): Store the first hash at the end
of the pool.
--

This fixes a long standing bug (since 1998) in Libgcrypt and GnuPG.
An attacker who obtains 580 bytes of the random number from the
standard RNG can trivially predict the next 20 bytes of output.

For use in GnuPG this bug does not affect the default generation of
keys because running gpg for key creation creates at most 2 keys from
the pool: For a single 4096 bit RSA key 512 byte of random are
required and thus for the second key (encryption subkey), 20 bytes
could be predicted from the the first key.  However, the security of
an OpenPGP key depends on the primary key (which was generated first)
and thus the 20 predictable bytes should not be a problem.  For the
default key length of 2048 bit nothing will be predictable.

For the former default of DSA+Elgamal key it is complicate to give an
answer: For 2048 bit keys a pool of 30 non-secret candidate primes of
about 300 bits each are first created.  This reads at least 1140 bytes
from the pool and thus parts could be predicted.  At some point a 256
bit secret is read from the pool; which in the worst case might be
partly predictable.

The bug was found and reported by Felix Dörre and Vladimir Klebanov,
Karlsruhe Institute of Technology.  A paper describing the problem in
detail will shortly be published.

CVE-id: CVE-2016-6313
Signed-off-by: Werner Koch <wk@gnupg.org>
CVE: CVE-2016-6313
CWE: CWE-200
Vulnerability description: The mixing functions in the random number generator in Libgcrypt before 1.5.6, 1.6.x before 1.6.6, and 1.7.x before 1.7.3 and GnuPG before 1.4.21 make it easier for attackers to obtain the values of 160 bits by leveraging knowledge of the previous 4640 bits.

Project: libgcrypt
File: random-csprng.c

_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;
}

Project: libgcrypt
File: random-csprng.c

random_poll()
{
  rndstats.slowpolls++;
  read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM);
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_fast_poll (void)
{
  initialize_basics ();

  lock_pool ();
  if (rndpool)
    {
      /* Yes, we are fully initialized. */
      do_fast_random_poll ();
    }
  unlock_pool ();
}

Project: libgcrypt
File: random-csprng.c

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;
    }
}

Project: libgcrypt
File: random-csprng.c

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;
}

Project: libgcrypt
File: random-csprng.c

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;
}

Project: libgcrypt
File: random-csprng.c

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;
}

Project: libgcrypt
File: random-csprng.c

_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)":"");
}

Project: libgcrypt
File: random-csprng.c

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);
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_is_faked (void)
{
  /* We need to initialize due to the runtime determination of
     available entropy gather modules.  */
  initialize();
  return quick_test;
}

Project: libgcrypt
File: random-csprng.c

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 ();
}

Project: libgcrypt
File: random-csprng.c

_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 = 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 ();
}

Project: libgcrypt
File: random-csprng.c

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;
}

Project: libgcrypt
File: random-csprng.c

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);
    }
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_set_seed_file (const char *name)
{
  if (seed_file_name)
    BUG ();
  seed_file_name = xstrdup (name);
}

Project: libgcrypt
File: random-csprng.c

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");
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_enable_quick_gen (void)
{
  quick_test = 1;
}

Project: libgcrypt
File: random-csprng.c

_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 ();
}

Project: libgcrypt
File: random-csprng.c

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*/
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_secure_alloc (void)
{
  secure_alloc = 1;
}

Project: libgcrypt
File: random-csprng.c

_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*/
}

Project: libgcrypt
File: random-csprng.c

_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 ();
}

Project: libgcrypt
File: random-csprng.c

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);
}

Project: libgcrypt
File: random-csprng.c

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;
	}
    }
}

Project: libgcrypt
File: random-csprng.c

_gcry_rngcsprng_initialize (int full)
{
  if (!full)
    initialize_basics ();
  else
    initialize ();
}

Project: libgcrypt
File: random-csprng.c

_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*/
}

Project: libgcrypt
File: random-csprng.c

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));
}