commit-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[hurd] 02/43: trans: New random translator.


From: Samuel Thibault
Subject: [hurd] 02/43: trans: New random translator.
Date: Mon, 11 Sep 2017 07:10:08 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch upstream
in repository hurd.

commit 29ff193d27436e52d8112903c882ebe52f071d88
Author: Justus Winter <address@hidden>
Date:   Fri Jun 2 00:47:07 2017 +0200

    trans: New random translator.
    
    Previously, the Hurd included a translator providing /dev/random and
    /dev/urandom based on a source copy of the random number generator
    found in classic GnuPG.
    
    The new random translator is using the SHAKE128 algorithm from the
    SHA-3 family as the underlying cryptographic primitive.  Being a
    sponge construction, it allows the extraction of arbitrary amounts of
    pseudorandom data.  It is continuously fed entropy by hashing system
    state that is hard to predict.
    
    * Makefile (prog-subdirs): Remove 'random'.
    * NEWS: Update.
    * random/Makefile: Delete file.
    * random/TODO: Likewise.
    * random/gnupg-bithelp.h: Likewise.
    * random/gnupg-glue.h: Likewise.
    * random/gnupg-random.c: Likewise.
    * random/gnupg-random.h: Likewise.
    * random/gnupg-rmd.h: Likewise.
    * random/gnupg-rmd160.c: Likewise.
    * random/random.h: Likewise.
    * sutils/MAKEDEV.sh (random): Create node.
    (urandom): The new translator is both secure and non-blocking.  Create
    a link from urandom to random for compatibility with Linux.
    * trans/Makefile (targets): Add 'random'.
    * trans/random.c: Move the skeleton of the old random translator here,
    but replace the PRNG with SHAKE128.  Remove all dubious attempts of
    accounting for entropy.  Do not block ever.
---
 Makefile                   |   1 -
 NEWS                       |   4 +
 random/Makefile            |  30 --
 random/TODO                |  11 -
 random/gnupg-bithelp.h     |  41 ---
 random/gnupg-glue.h        |  40 ---
 random/gnupg-random.c      | 809 ---------------------------------------------
 random/gnupg-random.h      |  47 ---
 random/gnupg-rmd.h         |  38 ---
 random/gnupg-rmd160.c      | 655 ------------------------------------
 random/random.h            |  32 --
 sutils/MAKEDEV.sh          |   8 +-
 trans/Makefile             |   9 +-
 {random => trans}/random.c | 500 ++++++++++++++++------------
 14 files changed, 303 insertions(+), 1922 deletions(-)

diff --git a/Makefile b/Makefile
index 9de4fa8..119f130 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,6 @@ prog-subdirs = auth proc exec term \
               hostmux usermux ftpfs trans \
               console-client utils sutils \
               benchmarks fstests \
-              random \
               procfs \
               startup \
               init \
diff --git a/NEWS b/NEWS
index 1b500be..9482185 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,10 @@ Subhurd's processes are now properly embedded in the 
Motherhurds
 process hierarchy.  They can be inspected and debugged just like any
 other process.
 
+The random translator has been reimplemented using the SHAKE128
+algorithm from the SHA-3 family as the underlying cryptographic
+primitive.
+
 Version 0.9 (2016-12-18)
 
 The 'boot' program can now be run as unprivileged user, allowing any
diff --git a/random/Makefile b/random/Makefile
deleted file mode 100644
index 5f8a62c..0000000
--- a/random/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-#   Copyright (C) 1994,95,96,97,99,2000,2001 Free Software Foundation, Inc.
-#
-#   This program is free software; you can redistribute it and/or
-#   modify it under the terms of the GNU General Public License as
-#   published by the Free Software Foundation; either version 2, or (at
-#   your option) any later version.
-#
-#   This program 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
-#   General Public License for more details.
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program; if not, write to the Free Software
-#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-dir := random
-makemode := server
-
-CFLAGS += -D__HURD__
-
-target = random
-SRCS = random.c gnupg-random.c gnupg-rmd160.c
-OBJS = $(SRCS:.c=.o) startup_notifyServer.o
-LCLHDRS = gnupg-random.h gnupg-rmd.h gnupg-bithelp.h random.h
-HURDLIBS = trivfs ports fshelp ihash iohelp shouldbeinlibc
-LDLIBS = -lpthread
-
-include ../Makeconf
diff --git a/random/TODO b/random/TODO
deleted file mode 100644
index 9cc57ab..0000000
--- a/random/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-* read_poll uses random_poll until the pool is filled.  This is ian
-  issue at first initialization, as this requries POOLSIZE good random (level 
1 from
-  gather_random) even in level 0 and 1.
-  For now, the code is only applied to level 2.  Eventually, readable_pool
-  should be fixed to return 0 if initialization is not done yet and not enough 
bytes
-  are available.  Otherwise it enters an infinite loop.
-
-* Permissions?
-
-* Off by one error in gather_random/io_write?  I can only get GATHERBUFSIZE - 1
-  bytes from it.
diff --git a/random/gnupg-bithelp.h b/random/gnupg-bithelp.h
deleted file mode 100644
index 188db16..0000000
--- a/random/gnupg-bithelp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* bithelp.h  -  Some bit manipulation helpers
- *     Copyright (C) 1999 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-#ifndef G10_BITHELP_H
-#define G10_BITHELP_H
-
-
-/****************
- * Rotate a 32 bit integer by n bytes
- */
-#if defined(__GNUC__) && defined(__i386__)
-static inline u32
-rol( u32 x, int n)
-{
-       __asm__("roll %%cl,%0"
-               :"=r" (x)
-               :"0" (x),"c" (n));
-       return x;
-}
-#else
-  #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
-#endif
-
-
-#endif /*G10_BITHELP_H*/
diff --git a/random/gnupg-glue.h b/random/gnupg-glue.h
deleted file mode 100644
index cbf0a10..0000000
--- a/random/gnupg-glue.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __GNUPG_GLUE_H__
-#define __GNUPG_GLUE_H__
-
-#include <sys/types.h>
-#include <random.h>
-
-#define SIZEOF_UNSIGNED_LONG 4
-typedef unsigned int u32;
-typedef unsigned char byte;
-
-/* GnuPG's config.h  */
-#define HAVE_GETTIMEOFDAY 1
-#define HAVE_GETRUSAGE 1
-#define HAVE_RAND 1
-
-/* GnuPG's memory.h  */
-#define m_alloc malloc
-#define m_alloc_secure malloc
-#define m_alloc_clear(x) calloc(x, 1)
-#define m_alloc_secure_clear(x) calloc(x, 1)
-#define m_free free
-#define m_strdup strdup
-
-/* GnuPG's dynaload.h  */
-#define dynload_getfnc_fast_random_poll() (0)
-#define dynload_getfnc_gather_random() &gather_random
-int
-gather_random( void (*add)(const void*, size_t, int), int requester,
-               size_t length, int level );
-
-/* GnuPG's miscellaneous stuff.  */
-#define BUG() assert(0)
-#define _(x) x
-#define make_timestamp() time(0)
-#define tty_printf printf
-#define log_info(format, args...) printf(format , ## args)
-#define log_fatal(format, args...) { printf(format , ## args) ; exit(2); }
-#define DIM(v) (sizeof(v)/sizeof((v)[0]))
-
-#endif /* __GNUPG_GLUE_H__ */
diff --git a/random/gnupg-random.c b/random/gnupg-random.c
deleted file mode 100644
index a4df694..0000000
--- a/random/gnupg-random.c
+++ /dev/null
@@ -1,809 +0,0 @@
-/* random.c  - random number generator
- *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-/****************
- * This random number generator is modelled after the one described
- * in Peter Gutmann's Paper: "Software Generation of Practically
- * Strong Random Numbers".
- */
-
-#ifndef __HURD__
-#include <config.h>
-#else
-#include "gnupg-glue.h"
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#ifdef HAVE_GETHRTIME
-  #include <sys/times.h>
-#endif
-#ifdef HAVE_GETTIMEOFDAY
-  #include <sys/times.h>
-#endif
-#ifdef HAVE_GETRUSAGE
-  #include <sys/resource.h>
-#endif
-#ifdef __MINGW32__
-  #include <process.h>
-#endif
-#ifndef __HURD__
-#include "util.h"
-#endif
-#ifndef __HURD__
-#include "rmd.h"
-#include "ttyio.h"
-#include "i18n.h"
-#include "random.h"
-#include "rand-internal.h"
-#include "dynload.h"
-#else
-#include "gnupg-rmd.h"
-#include "gnupg-random.h"
-#endif
-
-#ifndef RAND_MAX   /* for SunOS */
-  #define RAND_MAX 32767
-#endif
-
-
-#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
-
-#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
- * and poolsize must be a multiple of the digest length
- * to make the AND operations faster, the size should also be
- * a multiple of ulong
- */
-#define POOLBLOCKS 30
-#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
-#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
-  #error Please make sure that poolsize is a multiple of ulong
-#endif
-#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
-
-
-static int is_initialized;
-#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
-static byte *rndpool;  /* allocated size is POOLSIZE+BLOCKLEN */
-static byte *keypool;  /* allocated size is POOLSIZE+BLOCKLEN */
-static size_t pool_readpos;
-static size_t pool_writepos;
-static int pool_filled;
-static int pool_balance;
-static int just_mixed;
-static int did_initial_extra_seeding;
-static char *seed_file_name;
-static int allow_seed_file_update;
-
-static int secure_alloc;
-static int quick_test;
-static int faked_rng;
-
-
-#ifndef __HURD__
-static void read_pool( byte *buffer, size_t length, int level );
-#else
-int read_pool( byte *buffer, size_t length, int level );
-#endif
-static void add_randomness( const void *buffer, size_t length, int source );
-static void random_poll(void);
-#ifndef __HURD__
-static void read_random_source( int requester, size_t length, int level);
-#else
-static int read_random_source( int requester, size_t length, int level);
-#endif
-static int gather_faked( void (*add)(const void*, size_t, int), int requester,
-                                                   size_t length, int level );
-
-static struct {
-    ulong mixrnd;
-    ulong mixkey;
-    ulong slowpolls;
-    ulong fastpolls;
-    ulong getbytes1;
-    ulong ngetbytes1;
-    ulong getbytes2;
-    ulong ngetbytes2;
-    ulong addbytes;
-    ulong naddbytes;
-} rndstats;
-
-static void
-initialize(void)
-{
-    /* 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 ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
-                          : m_alloc_clear(POOLSIZE+BLOCKLEN);
-    keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
-                          : m_alloc_clear(POOLSIZE+BLOCKLEN);
-    is_initialized = 1;
-#ifndef __HURD__
-    cipher_modules_constructor();
-#endif
-}
-
-static void
-burn_stack (int bytes)
-{
-    char buf[128];
-    
-    memset (buf, 0, sizeof buf);
-    bytes -= sizeof buf;
-    if (bytes > 0)
-        burn_stack (bytes);
-}
-
-void
-random_dump_stats()
-{
-    fprintf(stderr,
-           "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
-           "              outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
-       POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
-                 rndstats.naddbytes, rndstats.addbytes,
-       rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
-                   rndstats.ngetbytes2, rndstats.getbytes2 );
-}
-
-void
-secure_random_alloc()
-{
-    secure_alloc = 1;
-}
-
-
-int
-quick_random_gen( int onoff )
-{
-    int last;
-
-    read_random_source(0,0,0); /* init */
-    last = quick_test;
-    if( onoff != -1 )
-       quick_test = onoff;
-    return faked_rng? 1 : last;
-}
-
-
-/****************
- * Fill the buffer with LENGTH bytes of cryptographically strong
- * random bytes. level 0 is not very strong, 1 is strong enough
- * for most usage, 2 is good for key generation stuff but may be very slow.
- */
-void
-randomize_buffer( byte *buffer, size_t length, int level )
-{
-    byte *p = get_random_bits( length*8, level, 1 );
-    memcpy( buffer, p, length );
-    m_free(p);
-}
-
-
-int
-random_is_faked()
-{
-    if( !is_initialized )
-       initialize();
-    return faked_rng || quick_test;
-}
-
-/****************
- * Return a pointer to a randomized buffer of level 0 and LENGTH bits
- * caller must free the buffer.
- * Note: The returned value is rounded up to bytes.
- */
-byte *
-get_random_bits( size_t nbits, int level, int secure )
-{
-    byte *buf, *p;
-    size_t nbytes = (nbits+7)/8;
-
-    if( quick_test && level > 1 )
-       level = 1;
-    MASK_LEVEL(level);
-    if( level == 1 ) {
-       rndstats.getbytes1 += nbytes;
-       rndstats.ngetbytes1++;
-    }
-    else if( level >= 2 ) {
-       rndstats.getbytes2 += nbytes;
-       rndstats.ngetbytes2++;
-    }
-
-    buf = secure && secure_alloc ? m_alloc_secure( nbytes ) : m_alloc( nbytes 
);
-    for( p = buf; nbytes > 0; ) {
-       size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
-#ifdef __HURD__
-       n =
-#endif
-       read_pool( p, n, level );
-       nbytes -= n;
-       p += n;
-
-    }
-    return buf;
-}
-
-
-/****************
- * Mix the pool
- */
-static void
-mix_pool(byte *pool)
-{
-    byte *hashbuf = pool + POOLSIZE;
-    byte *p, *pend;
-    int i, n;
-    RMD160_CONTEXT md;
-
-    rmd160_init( &md );
- #if DIGESTLEN != 20
-    #error must have a digest length of 20 for ripe-md-160
- #endif
-    /* pool -> pool' */
-    pend = pool + POOLSIZE;
-    memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
-    memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
-    rmd160_mixblock( &md, hashbuf);
-    memcpy(pool, hashbuf, DIGESTLEN);
-
-    /* Loop for the remaining iterations.  */
-    p = pool;
-    for( n=1; n < POOLBLOCKS; n++ ) {
-       if( p + BLOCKLEN < pend )
-           memcpy(hashbuf, p, BLOCKLEN);
-       else {
-           byte *pp = p;
-           for(i=0; i < BLOCKLEN; i++ ) {
-               if( pp >= pend )
-                   pp = pool;
-               hashbuf[i] = *pp++;
-           }
-       }
-
-       rmd160_mixblock( &md, hashbuf);
-       p += DIGESTLEN;
-       memcpy(p, hashbuf, DIGESTLEN);
-    }
-    burn_stack (200); /* for the rmd160_mixblock() */
-}
-
-
-void
-set_random_seed_file( const char *name )
-{
-    if( seed_file_name )
-       BUG();
-    seed_file_name = m_strdup( name );
-}
-
-/****************
- * Read in a seed form the random_seed file
- * and return true if this was successful
- */
-static int
-read_seed_file()
-{
-    int fd;
-    struct stat sb;
-    byte buffer[POOLSIZE];
-    int n;
-
-    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( 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);
-       return 0;
-    }
-
-    close(fd);
-
-    add_randomness( buffer, POOLSIZE, 0 );
-    /* add some minor entropy to the pool now (this will also force a mixing) 
*/
-    {  pid_t x = getpid();
-       add_randomness( &x, sizeof(x), 0 );
-    }
-    {  time_t x = time(NULL);
-       add_randomness( &x, sizeof(x), 0 );
-    }
-    {  clock_t x = clock();
-       add_randomness( &x, sizeof(x), 0 );
-    }
-    /* 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 to much as we
-     * want to be friendly to the scare system entropy resource. */
-    read_random_source( 0, 16, 0 );
-
-    allow_seed_file_update = 1;
-    return 1;
-}
-
-void
-update_random_seed_file()
-{
-    ulong *sp, *dp;
-    int fd, i;
-
-    if( !seed_file_name || !is_initialized || !pool_filled )
-       return;
-    if( !allow_seed_file_update ) {
-       log_info(_("note: random_seed file not updated\n"));
-       return;
-    }
-
-
-    /* copy the entropy pool to a scratch pool and mix both of them */
-    for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
-                                   i < POOLWORDS; i++, dp++, sp++ ) {
-       *dp = *sp + ADD_VALUE;
-    }
-    mix_pool(rndpool); rndstats.mixrnd++;
-    mix_pool(keypool); rndstats.mixkey++;
-
-  #ifdef HAVE_DOSISH_SYSTEM
-    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
-                                                       S_IRUSR|S_IWUSR );
-  #else
-    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
-  #endif
-    if( fd == -1 ) {
-       log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) 
);
-       return;
-    }
-    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) );
-}
-
-#ifdef __HURD__
-int readable_pool( size_t length, int level )
-{
-  size_t needed = 0;
-  size_t my_balance = pool_balance;
-  size_t available = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
-
-  if (length > POOLSIZE)
-    length = POOLSIZE;
-
-  if (level < 2)
-    return length;
-
-  if( !pool_filled ) {
-    if( read_seed_file() )
-      pool_filled = 1;
-  }
-
-  if (!did_initial_extra_seeding)
-    {
-      /* Take account for initial extra seeding.  */
-      needed = length;
-      if (needed < POOLSIZE/2)
-       needed = POOLSIZE/2;
-      my_balance = needed;
-
-      if (!pool_filled && pool_writepos + needed < POOLSIZE)
-       {
-         /* If the pool is not filled yet, we couldn't read the seed
-            file.  Too bad.  We will now have to take account for so many
-            random_poll()s as fit into the remaining pool.  */
-         
-         needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / 
(POOLSIZE/5);
-       }
-    }
-  else
-    {
-      if (!pool_filled)
-       needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / 
(POOLSIZE/5);
-    }
-
-  /* NEEDED contains the bytes needed for initialization, MY_BALANCE the 
resulting
-     available bytes.  */
-  if (available < needed)
-    return 0;
-  return available + my_balance - needed;
-}
-#endif
-
-#ifndef __HURD__
-static void
-#else
-int
-#endif
-read_pool( byte *buffer, size_t length, int level )
-{
-    int i;
-    ulong *sp, *dp;
-
-    if( length > POOLSIZE ) {
-#ifndef __HURD__
-       log_fatal(_("too many random bits requested; the limit is %d\n"),
-                 POOLSIZE*8-1 );
-#else
-       length = POOLSIZE;
-#endif
-    }
-
-    if( !pool_filled ) {
-       if( read_seed_file() )
-           pool_filled = 1;
-    }
-
-    /* For level 2 quality (key generation) we alwas make
-     * sure that the pool has been seeded enough initially */
-    if( level == 2 && !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();
-#ifdef __HURD__
-       needed =
-#endif
-       read_random_source( 3, needed, 2 );
-#ifdef __HURD__
-       if (! needed)
-         return 0;
-       /* XXX This will succeed with needed < POOLSIZE/2 even.  But
-          erroring out will waste the random we already got.  */
-#endif
-       pool_balance += needed;
-       did_initial_extra_seeding=1;
-    }
-
-    /* for level 2 make sure that there is enough random in the pool */
-    if( level == 2 && pool_balance < length ) {
-       size_t needed;
-
-       if( pool_balance < 0 )
-           pool_balance = 0;
-       needed = length - pool_balance;
-       if( needed > POOLSIZE )
-           BUG();
-#ifdef __HURD__
-       needed =
-#endif
-       read_random_source( 3, needed, 2 );
-       pool_balance += needed;
-    }
-
-#ifdef __HURD__
-    /* XXX This makes level 0 and 1 worse than needed at first start up.  */
-    if (level == 2)
-#endif
-    /* make sure the pool is filled */
-    while( !pool_filled )
-       random_poll();
-
-    /* do always a fast random poll */
-    fast_random_poll();
-
-    if( !level ) { /* no need for cryptographic strong random */
-       /* create a new pool */
-       for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
-                                   i < POOLWORDS; i++, dp++, sp++ )
-           *dp = *sp + ADD_VALUE;
-       /* must mix both pools */
-       mix_pool(rndpool); rndstats.mixrnd++;
-       mix_pool(keypool); rndstats.mixkey++;
-       memcpy( buffer, keypool, length );
-       return length;
-    }
-    else {
-#ifdef __HURD__
-      int amount;
-#endif
-       /* 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=(ulong*)keypool, sp=(ulong*)rndpool;
-                                   i < POOLWORDS; i++, dp++, sp++ )
-           *dp = *sp + ADD_VALUE;
-       /* and mix both pools */
-       mix_pool(rndpool); rndstats.mixrnd++;
-       mix_pool(keypool); rndstats.mixkey++;
-       /* read the required data
-        * we use a readpointer to read from a different position each
-        * time */
-#ifdef __HURD__
-       if (level == 2 && length > pool_balance)
-         length = pool_balance;
-       amount = length;
-#endif
-       while( length-- ) {
-           *buffer++ = keypool[pool_readpos++];
-           if( pool_readpos >= POOLSIZE )
-               pool_readpos = 0;
-           pool_balance--;
-       }
-       if( pool_balance < 0 )
-           pool_balance = 0;
-       /* and clear the keypool */
-       memset( keypool, 0, POOLSIZE );
-#ifdef __HURD__
-       return amount;
-#endif
-    }
-}
-
-
-/****************
- * Add LENGTH bytes of randomness from buffer to the pool.
- * source may be used to specify the randomness source.
- * Source is:
- *     0 - used ony for initialization
- *     1 - fast random poll function
- *     2 - normal poll function
- *     3 - used when level 2 random quality has been requested
- *         to do an extra pool seed.
- */
-static void
-add_randomness( const void *buffer, size_t length, int source )
-{
-    const byte *p = buffer;
-
-    if( !is_initialized )
-       initialize();
-    rndstats.addbytes += length;
-    rndstats.naddbytes++;
-    while( length-- ) {
-       rndpool[pool_writepos++] = *p++;
-       if( pool_writepos >= POOLSIZE ) {
-           if( source > 1 )
-               pool_filled = 1;
-           pool_writepos = 0;
-           mix_pool(rndpool); rndstats.mixrnd++;
-           just_mixed = !length;
-       }
-    }
-}
-
-
-
-static void
-random_poll()
-{
-    rndstats.slowpolls++;
-    read_random_source( 2, POOLSIZE/5, 1 );
-}
-
-
-void
-fast_random_poll()
-{
-    static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
-    static int initialized = 0;
-
-    rndstats.fastpolls++;
-    if( !initialized ) {
-       if( !is_initialized )
-           initialize();
-       initialized = 1;
-       fnc = dynload_getfnc_fast_random_poll();
-    }
-    if( fnc ) {
-       (*fnc)( add_randomness, 1 );
-       return;
-    }
-
-    /* fall back to the generic function */
-  #if HAVE_GETHRTIME
-    {  hrtime_t tv;
-       tv = gethrtime();
-       add_randomness( &tv, sizeof(tv), 1 );
-    }
-  #elif HAVE_GETTIMEOFDAY
-    {  struct timeval tv;
-       if( gettimeofday( &tv, NULL ) )
-           BUG();
-       add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
-       add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
-    }
-  #elif HAVE_CLOCK_GETTIME
-    {  struct timespec tv;
-       if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
-           BUG();
-       add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
-       add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
-    }
-  #else /* use times */
-    #ifndef HAVE_DOSISH_SYSTEM
-    {  struct tms buf;
-       times( &buf );
-       add_randomness( &buf, sizeof buf, 1 );
-    }
-    #endif
-  #endif
-  #ifdef HAVE_GETRUSAGE
-    #ifndef RUSAGE_SELF
-      #ifdef __GCC__
-       #warning There is no RUSAGE_SELF on this system
-      #endif
-    #else
-    {  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 
-         * ognore all error codes and hope for the best
-         */
-        getrusage( RUSAGE_SELF, &buf );
-        
-       add_randomness( &buf, sizeof buf, 1 );
-       memset( &buf, 0, sizeof buf );
-    }
-    #endif
-  #endif
-    /* 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), 1 );
-    }
-    {  clock_t x = clock();
-       add_randomness( &x, sizeof(x), 1 );
-    }
-}
-
-
-#ifndef __HURD__
-static void
-#else
-static int
-#endif
-read_random_source( int requester, size_t length, int level )
-{
-    static int (*fnc)(void (*)(const void*, size_t, int), int,
-                                                   size_t, int) = NULL;
-#ifdef __HURD__
-    int got;
-#endif
-    if( !fnc ) {
-       if( !is_initialized )
-           initialize();
-       fnc = dynload_getfnc_gather_random();
-       if( !fnc ) {
-           faked_rng = 1;
-           fnc = gather_faked;
-       }
-       if( !requester && !length && !level )
-#ifndef __HURD__
-           return; /* init only */
-#else
-           return 0;
-#endif
-    }
-#ifndef __HURD__
-    if( (*fnc)( add_randomness, requester, length, level ) < 0 )
-        log_fatal("No way to gather entropy for the RNG\n");
-#else
-    got = (*fnc)( add_randomness, requester, length, level );
-    if (got < 0)
-        log_fatal("No way to gather entropy for the RNG\n");
-    return got;
-#endif
-}
-
-
-static int
-gather_faked( void (*add)(const void*, size_t, int), int requester,
-             size_t length, int level )
-{
-    static int initialized=0;
-    size_t n;
-    char *buffer, *p;
-
-    if( !initialized ) {
-       log_info(_("WARNING: using insecure random number generator!!\n"));
-       tty_printf(_("The random number generator is only a kludge to let\n"
-                  "it run - it is in no way a strong RNG!\n\n"
-                  "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
-       initialized=1;
-      #ifdef HAVE_RAND
-       srand(make_timestamp()*getpid());
-      #else
-       srandom(make_timestamp()*getpid());
-      #endif
-    }
-    printf("WAITING FOR %i bytes.\n", length);
-    p = buffer = m_alloc( 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, requester );
-    m_free(buffer);
-    return 0; /* okay */
-}
-
diff --git a/random/gnupg-random.h b/random/gnupg-random.h
deleted file mode 100644
index ee18feb..0000000
--- a/random/gnupg-random.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* random.h - random functions
- *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-#ifndef G10_RANDOM_H
-#define G10_RANDOM_H
-
-#ifndef __HURD__
-#include "types.h"
-#else
-#include "gnupg-glue.h"
-int read_pool (byte *, size_t, int);
-int readable_pool (size_t, int);
-#endif
-
-/*-- random.c --*/
-void random_dump_stats(void);
-void secure_random_alloc(void);
-void set_random_seed_file(const char *);
-void update_random_seed_file(void);
-int  quick_random_gen( int onoff );
-int  random_is_faked(void);
-void randomize_buffer( byte *buffer, size_t length, int level );
-byte *get_random_bits( size_t nbits, int level, int secure );
-void fast_random_poll( void );
-
-/*-- rndw32.c --*/
-#ifdef USE_STATIC_RNDW32
-void rndw32_set_dll_name( const char *name );
-#endif
-
-#endif /*G10_RANDOM_H*/
diff --git a/random/gnupg-rmd.h b/random/gnupg-rmd.h
deleted file mode 100644
index 102624a..0000000
--- a/random/gnupg-rmd.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* rmd.h - RIPE-MD hash functions
- *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-#ifndef G10_RMD_H
-#define G10_RMD_H
-
-#ifdef __HURD__
-#include "gnupg-glue.h"
-#endif
-
-/* we need this here because random.c must have direct access */
-typedef struct {
-    u32  h0,h1,h2,h3,h4;
-    u32  nblocks;
-    byte buf[64];
-    int  count;
-} RMD160_CONTEXT;
-
-void rmd160_init( RMD160_CONTEXT *hd );
-void rmd160_mixblock( RMD160_CONTEXT *hd, byte *buffer );
-
-#endif /*G10_RMD_H*/
diff --git a/random/gnupg-rmd160.c b/random/gnupg-rmd160.c
deleted file mode 100644
index 8f4207b..0000000
--- a/random/gnupg-rmd160.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/* rmd160.c  - RIPE-MD160
- *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef __HURD__
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#ifndef __HURD__
-#include "util.h"
-#include "memory.h"
-#include "rmd.h"
-#include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
-#include "dynload.h"
-
-#include "bithelp.h"
-#else
-#include "gnupg-rmd.h"
-#include "gnupg-bithelp.h"
-#endif
-
-
-/*********************************
- * RIPEMD-160 is not patented, see (as of 25.10.97)
- *   http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
- * Note that the code uses Little Endian byteorder, which is good for
- * 386 etc, but we must add some conversion when used on a big endian box.
- *
- *
- * Pseudo-code for RIPEMD-160
- *
- * RIPEMD-160 is an iterative hash function that operates on 32-bit words.
- * The round function takes as input a 5-word chaining variable and a 16-word
- * message block and maps this to a new chaining variable. All operations are
- * defined on 32-bit words. Padding is identical to that of MD4.
- *
- *
- * RIPEMD-160: definitions
- *
- *
- *   nonlinear functions at bit level: exor, mux, -, mux, -
- *
- *   f(j, x, y, z) = x XOR y XOR z               (0 <= j <= 15)
- *   f(j, x, y, z) = (x AND y) OR (NOT(x) AND z)  (16 <= j <= 31)
- *   f(j, x, y, z) = (x OR NOT(y)) XOR z         (32 <= j <= 47)
- *   f(j, x, y, z) = (x AND z) OR (y AND NOT(z))  (48 <= j <= 63)
- *   f(j, x, y, z) = x XOR (y OR NOT(z))         (64 <= j <= 79)
- *
- *
- *   added constants (hexadecimal)
- *
- *   K(j) = 0x00000000     (0 <= j <= 15)
- *   K(j) = 0x5A827999    (16 <= j <= 31)      int(2**30 x sqrt(2))
- *   K(j) = 0x6ED9EBA1    (32 <= j <= 47)      int(2**30 x sqrt(3))
- *   K(j) = 0x8F1BBCDC    (48 <= j <= 63)      int(2**30 x sqrt(5))
- *   K(j) = 0xA953FD4E    (64 <= j <= 79)      int(2**30 x sqrt(7))
- *   K'(j) = 0x50A28BE6     (0 <= j <= 15)      int(2**30 x cbrt(2))
- *   K'(j) = 0x5C4DD124    (16 <= j <= 31)      int(2**30 x cbrt(3))
- *   K'(j) = 0x6D703EF3    (32 <= j <= 47)      int(2**30 x cbrt(5))
- *   K'(j) = 0x7A6D76E9    (48 <= j <= 63)      int(2**30 x cbrt(7))
- *   K'(j) = 0x00000000    (64 <= j <= 79)
- *
- *
- *   selection of message word
- *
- *   r(j)      = j                   (0 <= j <= 15)
- *   r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
- *   r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
- *   r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
- *   r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
- *   r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
- *   r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
- *   r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
- *   r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
- *   r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
- *
- *
- *   amount for rotate left (rol)
- *
- *   s(0..15)  = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
- *   s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
- *   s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
- *   s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
- *   s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
- *   s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
- *   s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
- *   s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
- *   s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
- *   s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
- *
- *
- *   initial value (hexadecimal)
- *
- *   h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
- *                                                     h4 = 0xC3D2E1F0;
- *
- *
- * RIPEMD-160: pseudo-code
- *
- *   It is assumed that the message after padding consists of t 16-word blocks
- *   that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
- *   The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
- *   shift (rotate) over s positions.
- *
- *
- *   for i := 0 to t-1 {
- *      A := h0; B := h1; C := h2; D = h3; E = h4;
- *      A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
- *      for j := 0 to 79 {
- *          T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
- *          A := E; E := D; D := rol_10(C); C := B; B := T;
- *          T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
-                                                      [+] K'(j)) [+] E';
- *          A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
- *      }
- *      T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
- *      h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
- *   }
- */
-
-/* Some examples:
- * ""                    9c1185a5c5e9fc54612808977ee8f548b2258d31
- * "a"                   0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
- * "abc"                 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
- * "message digest"      5d0689ef49d2fae572b881b123a85ffa21595f36
- * "a...z"               f71c27109c692c1b56bbdceb5b9d2865b3708dbc
- * "abcdbcde...nopq"     12a053384a9c0c88e405a06c27dcf49ada62eb2b
- * "A...Za...z0...9"     b0e20b6e3116640286ed3a87a5713079b21f5189
- * 8 times "1234567890"  9b752e45573d4b39f4dbd3323cab82bf63326bfb
- * 1 million times "a"   52783243c1697bdbe16d37f97f68f08325dc1528
- */
-
-static void
-burn_stack (int bytes)
-{
-    char buf[150];
-    
-    memset (buf, 0, sizeof buf);
-    bytes -= sizeof buf;
-    if (bytes > 0)
-        burn_stack (bytes);
-}
-
-
-
-void
-rmd160_init( RMD160_CONTEXT *hd )
-{
-    hd->h0 = 0x67452301;
-    hd->h1 = 0xEFCDAB89;
-    hd->h2 = 0x98BADCFE;
-    hd->h3 = 0x10325476;
-    hd->h4 = 0xC3D2E1F0;
-    hd->nblocks = 0;
-    hd->count = 0;
-}
-
-
-
-/****************
- * Transform the message X which consists of 16 32-bit-words
- */
-static void
-transform( RMD160_CONTEXT *hd, byte *data )
-{
-    u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
-  #ifdef BIG_ENDIAN_HOST
-    u32 x[16];
-    { int i;
-      byte *p2, *p1;
-      for(i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
-       p2[3] = *p1++;
-       p2[2] = *p1++;
-       p2[1] = *p1++;
-       p2[0] = *p1++;
-      }
-    }
-  #else
-   #if 0
-    u32 *x =(u32*)data;
-   #else
-    /* this version is better because it is always aligned;
-     * The performance penalty on a 586-100 is about 6% which
-     * is acceptable - because the data is more local it might
-     * also be possible that this is faster on some machines.
-     * This function (when compiled with -02 on gcc 2.7.2)
-     * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
-     * [measured with a 4MB data and "gpgm --print-md rmd160"] */
-    u32 x[16];
-    memcpy( x, data, 64 );
-   #endif
-  #endif
-
-
-#define K0  0x00000000
-#define K1  0x5A827999
-#define K2  0x6ED9EBA1
-#define K3  0x8F1BBCDC
-#define K4  0xA953FD4E
-#define KK0 0x50A28BE6
-#define KK1 0x5C4DD124
-#define KK2 0x6D703EF3
-#define KK3 0x7A6D76E9
-#define KK4 0x00000000
-#define F0(x,y,z)   ( (x) ^ (y) ^ (z) )
-#define F1(x,y,z)   ( ((x) & (y)) | (~(x) & (z)) )
-#define F2(x,y,z)   ( ((x) | ~(y)) ^ (z) )
-#define F3(x,y,z)   ( ((x) & (z)) | ((y) & ~(z)) )
-#define F4(x,y,z)   ( (x) ^ ((y) | ~(z)) )
-#define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
-                                 a = rol(t,s) + e;            \
-                                 c = rol(c,10);               \
-                               } while(0)
-
-    /* left lane */
-    a = hd->h0;
-    b = hd->h1;
-    c = hd->h2;
-    d = hd->h3;
-    e = hd->h4;
-    R( a, b, c, d, e, F0, K0,  0, 11 );
-    R( e, a, b, c, d, F0, K0,  1, 14 );
-    R( d, e, a, b, c, F0, K0,  2, 15 );
-    R( c, d, e, a, b, F0, K0,  3, 12 );
-    R( b, c, d, e, a, F0, K0,  4,  5 );
-    R( a, b, c, d, e, F0, K0,  5,  8 );
-    R( e, a, b, c, d, F0, K0,  6,  7 );
-    R( d, e, a, b, c, F0, K0,  7,  9 );
-    R( c, d, e, a, b, F0, K0,  8, 11 );
-    R( b, c, d, e, a, F0, K0,  9, 13 );
-    R( a, b, c, d, e, F0, K0, 10, 14 );
-    R( e, a, b, c, d, F0, K0, 11, 15 );
-    R( d, e, a, b, c, F0, K0, 12,  6 );
-    R( c, d, e, a, b, F0, K0, 13,  7 );
-    R( b, c, d, e, a, F0, K0, 14,  9 );
-    R( a, b, c, d, e, F0, K0, 15,  8 );
-    R( e, a, b, c, d, F1, K1,  7,  7 );
-    R( d, e, a, b, c, F1, K1,  4,  6 );
-    R( c, d, e, a, b, F1, K1, 13,  8 );
-    R( b, c, d, e, a, F1, K1,  1, 13 );
-    R( a, b, c, d, e, F1, K1, 10, 11 );
-    R( e, a, b, c, d, F1, K1,  6,  9 );
-    R( d, e, a, b, c, F1, K1, 15,  7 );
-    R( c, d, e, a, b, F1, K1,  3, 15 );
-    R( b, c, d, e, a, F1, K1, 12,  7 );
-    R( a, b, c, d, e, F1, K1,  0, 12 );
-    R( e, a, b, c, d, F1, K1,  9, 15 );
-    R( d, e, a, b, c, F1, K1,  5,  9 );
-    R( c, d, e, a, b, F1, K1,  2, 11 );
-    R( b, c, d, e, a, F1, K1, 14,  7 );
-    R( a, b, c, d, e, F1, K1, 11, 13 );
-    R( e, a, b, c, d, F1, K1,  8, 12 );
-    R( d, e, a, b, c, F2, K2,  3, 11 );
-    R( c, d, e, a, b, F2, K2, 10, 13 );
-    R( b, c, d, e, a, F2, K2, 14,  6 );
-    R( a, b, c, d, e, F2, K2,  4,  7 );
-    R( e, a, b, c, d, F2, K2,  9, 14 );
-    R( d, e, a, b, c, F2, K2, 15,  9 );
-    R( c, d, e, a, b, F2, K2,  8, 13 );
-    R( b, c, d, e, a, F2, K2,  1, 15 );
-    R( a, b, c, d, e, F2, K2,  2, 14 );
-    R( e, a, b, c, d, F2, K2,  7,  8 );
-    R( d, e, a, b, c, F2, K2,  0, 13 );
-    R( c, d, e, a, b, F2, K2,  6,  6 );
-    R( b, c, d, e, a, F2, K2, 13,  5 );
-    R( a, b, c, d, e, F2, K2, 11, 12 );
-    R( e, a, b, c, d, F2, K2,  5,  7 );
-    R( d, e, a, b, c, F2, K2, 12,  5 );
-    R( c, d, e, a, b, F3, K3,  1, 11 );
-    R( b, c, d, e, a, F3, K3,  9, 12 );
-    R( a, b, c, d, e, F3, K3, 11, 14 );
-    R( e, a, b, c, d, F3, K3, 10, 15 );
-    R( d, e, a, b, c, F3, K3,  0, 14 );
-    R( c, d, e, a, b, F3, K3,  8, 15 );
-    R( b, c, d, e, a, F3, K3, 12,  9 );
-    R( a, b, c, d, e, F3, K3,  4,  8 );
-    R( e, a, b, c, d, F3, K3, 13,  9 );
-    R( d, e, a, b, c, F3, K3,  3, 14 );
-    R( c, d, e, a, b, F3, K3,  7,  5 );
-    R( b, c, d, e, a, F3, K3, 15,  6 );
-    R( a, b, c, d, e, F3, K3, 14,  8 );
-    R( e, a, b, c, d, F3, K3,  5,  6 );
-    R( d, e, a, b, c, F3, K3,  6,  5 );
-    R( c, d, e, a, b, F3, K3,  2, 12 );
-    R( b, c, d, e, a, F4, K4,  4,  9 );
-    R( a, b, c, d, e, F4, K4,  0, 15 );
-    R( e, a, b, c, d, F4, K4,  5,  5 );
-    R( d, e, a, b, c, F4, K4,  9, 11 );
-    R( c, d, e, a, b, F4, K4,  7,  6 );
-    R( b, c, d, e, a, F4, K4, 12,  8 );
-    R( a, b, c, d, e, F4, K4,  2, 13 );
-    R( e, a, b, c, d, F4, K4, 10, 12 );
-    R( d, e, a, b, c, F4, K4, 14,  5 );
-    R( c, d, e, a, b, F4, K4,  1, 12 );
-    R( b, c, d, e, a, F4, K4,  3, 13 );
-    R( a, b, c, d, e, F4, K4,  8, 14 );
-    R( e, a, b, c, d, F4, K4, 11, 11 );
-    R( d, e, a, b, c, F4, K4,  6,  8 );
-    R( c, d, e, a, b, F4, K4, 15,  5 );
-    R( b, c, d, e, a, F4, K4, 13,  6 );
-
-    aa = a; bb = b; cc = c; dd = d; ee = e;
-
-    /* right lane */
-    a = hd->h0;
-    b = hd->h1;
-    c = hd->h2;
-    d = hd->h3;
-    e = hd->h4;
-    R( a, b, c, d, e, F4, KK0, 5,  8);
-    R( e, a, b, c, d, F4, KK0, 14,  9);
-    R( d, e, a, b, c, F4, KK0, 7,  9);
-    R( c, d, e, a, b, F4, KK0, 0, 11);
-    R( b, c, d, e, a, F4, KK0, 9, 13);
-    R( a, b, c, d, e, F4, KK0, 2, 15);
-    R( e, a, b, c, d, F4, KK0, 11, 15);
-    R( d, e, a, b, c, F4, KK0, 4,  5);
-    R( c, d, e, a, b, F4, KK0, 13,  7);
-    R( b, c, d, e, a, F4, KK0, 6,  7);
-    R( a, b, c, d, e, F4, KK0, 15,  8);
-    R( e, a, b, c, d, F4, KK0, 8, 11);
-    R( d, e, a, b, c, F4, KK0, 1, 14);
-    R( c, d, e, a, b, F4, KK0, 10, 14);
-    R( b, c, d, e, a, F4, KK0, 3, 12);
-    R( a, b, c, d, e, F4, KK0, 12,  6);
-    R( e, a, b, c, d, F3, KK1, 6,  9);
-    R( d, e, a, b, c, F3, KK1, 11, 13);
-    R( c, d, e, a, b, F3, KK1, 3, 15);
-    R( b, c, d, e, a, F3, KK1, 7,  7);
-    R( a, b, c, d, e, F3, KK1, 0, 12);
-    R( e, a, b, c, d, F3, KK1, 13,  8);
-    R( d, e, a, b, c, F3, KK1, 5,  9);
-    R( c, d, e, a, b, F3, KK1, 10, 11);
-    R( b, c, d, e, a, F3, KK1, 14,  7);
-    R( a, b, c, d, e, F3, KK1, 15,  7);
-    R( e, a, b, c, d, F3, KK1, 8, 12);
-    R( d, e, a, b, c, F3, KK1, 12,  7);
-    R( c, d, e, a, b, F3, KK1, 4,  6);
-    R( b, c, d, e, a, F3, KK1, 9, 15);
-    R( a, b, c, d, e, F3, KK1, 1, 13);
-    R( e, a, b, c, d, F3, KK1, 2, 11);
-    R( d, e, a, b, c, F2, KK2, 15,  9);
-    R( c, d, e, a, b, F2, KK2, 5,  7);
-    R( b, c, d, e, a, F2, KK2, 1, 15);
-    R( a, b, c, d, e, F2, KK2, 3, 11);
-    R( e, a, b, c, d, F2, KK2, 7,  8);
-    R( d, e, a, b, c, F2, KK2, 14,  6);
-    R( c, d, e, a, b, F2, KK2, 6,  6);
-    R( b, c, d, e, a, F2, KK2, 9, 14);
-    R( a, b, c, d, e, F2, KK2, 11, 12);
-    R( e, a, b, c, d, F2, KK2, 8, 13);
-    R( d, e, a, b, c, F2, KK2, 12,  5);
-    R( c, d, e, a, b, F2, KK2, 2, 14);
-    R( b, c, d, e, a, F2, KK2, 10, 13);
-    R( a, b, c, d, e, F2, KK2, 0, 13);
-    R( e, a, b, c, d, F2, KK2, 4,  7);
-    R( d, e, a, b, c, F2, KK2, 13,  5);
-    R( c, d, e, a, b, F1, KK3, 8, 15);
-    R( b, c, d, e, a, F1, KK3, 6,  5);
-    R( a, b, c, d, e, F1, KK3, 4,  8);
-    R( e, a, b, c, d, F1, KK3, 1, 11);
-    R( d, e, a, b, c, F1, KK3, 3, 14);
-    R( c, d, e, a, b, F1, KK3, 11, 14);
-    R( b, c, d, e, a, F1, KK3, 15,  6);
-    R( a, b, c, d, e, F1, KK3, 0, 14);
-    R( e, a, b, c, d, F1, KK3, 5,  6);
-    R( d, e, a, b, c, F1, KK3, 12,  9);
-    R( c, d, e, a, b, F1, KK3, 2, 12);
-    R( b, c, d, e, a, F1, KK3, 13,  9);
-    R( a, b, c, d, e, F1, KK3, 9, 12);
-    R( e, a, b, c, d, F1, KK3, 7,  5);
-    R( d, e, a, b, c, F1, KK3, 10, 15);
-    R( c, d, e, a, b, F1, KK3, 14,  8);
-    R( b, c, d, e, a, F0, KK4, 12,  8);
-    R( a, b, c, d, e, F0, KK4, 15,  5);
-    R( e, a, b, c, d, F0, KK4, 10, 12);
-    R( d, e, a, b, c, F0, KK4, 4,  9);
-    R( c, d, e, a, b, F0, KK4, 1, 12);
-    R( b, c, d, e, a, F0, KK4, 5,  5);
-    R( a, b, c, d, e, F0, KK4, 8, 14);
-    R( e, a, b, c, d, F0, KK4, 7,  6);
-    R( d, e, a, b, c, F0, KK4, 6,  8);
-    R( c, d, e, a, b, F0, KK4, 2, 13);
-    R( b, c, d, e, a, F0, KK4, 13,  6);
-    R( a, b, c, d, e, F0, KK4, 14,  5);
-    R( e, a, b, c, d, F0, KK4, 0, 15);
-    R( d, e, a, b, c, F0, KK4, 3, 13);
-    R( c, d, e, a, b, F0, KK4, 9, 11);
-    R( b, c, d, e, a, F0, KK4, 11, 11);
-
-
-    t     = hd->h1 + d + cc;
-    hd->h1 = hd->h2 + e + dd;
-    hd->h2 = hd->h3 + a + ee;
-    hd->h3 = hd->h4 + b + aa;
-    hd->h4 = hd->h0 + c + bb;
-    hd->h0 = t;
-}
-
-
-/* Update the message digest with the contents
- * of INBUF with length INLEN.
- */
-static void
-rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
-{
-    if( hd->count == 64 ) { /* flush the buffer */
-       transform( hd, hd->buf );
-        burn_stack (108+5*sizeof(void*));
-       hd->count = 0;
-       hd->nblocks++;
-    }
-    if( !inbuf )
-       return;
-    if( hd->count ) {
-       for( ; inlen && hd->count < 64; inlen-- )
-           hd->buf[hd->count++] = *inbuf++;
-       rmd160_write( hd, NULL, 0 );
-       if( !inlen )
-           return;
-    }
-
-    while( inlen >= 64 ) {
-       transform( hd, inbuf );
-       hd->count = 0;
-       hd->nblocks++;
-       inlen -= 64;
-       inbuf += 64;
-    }
-    burn_stack (108+5*sizeof(void*));
-    for( ; inlen && hd->count < 64; inlen-- )
-       hd->buf[hd->count++] = *inbuf++;
-}
-
-/****************
- * Apply the rmd160 transform function on the buffer which must have
- * a length 64 bytes. Do not use this function together with the
- * other functions, use rmd160_init to initialize internal variables.
- * Returns: 16 bytes in buffer with the mixed contentes of buffer.
- */
-void
-rmd160_mixblock( RMD160_CONTEXT *hd, byte *buffer )
-{
-    byte *p = buffer;
-    transform( hd, buffer );
-  #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
-    X(0);
-    X(1);
-    X(2);
-    X(3);
-    X(4);
-  #undef X
-}
-
-
-/* The routine terminates the computation
- */
-
-static void
-rmd160_final( RMD160_CONTEXT *hd )
-{
-    u32 t, msb, lsb;
-    byte *p;
-
-    rmd160_write(hd, NULL, 0); /* flush */;
-
-    t = hd->nblocks;
-    /* multiply by 64 to make a byte count */
-    lsb = t << 6;
-    msb = t >> 26;
-    /* add the count */
-    t = lsb;
-    if( (lsb += hd->count) < t )
-       msb++;
-    /* multiply by 8 to make a bit count */
-    t = lsb;
-    lsb <<= 3;
-    msb <<= 3;
-    msb |= t >> 29;
-
-    if( hd->count < 56 ) { /* enough room */
-       hd->buf[hd->count++] = 0x80; /* pad */
-       while( hd->count < 56 )
-           hd->buf[hd->count++] = 0;  /* pad */
-    }
-    else { /* need one extra block */
-       hd->buf[hd->count++] = 0x80; /* pad character */
-       while( hd->count < 64 )
-           hd->buf[hd->count++] = 0;
-       rmd160_write(hd, NULL, 0);  /* flush */;
-       memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
-    }
-    /* append the 64 bit count */
-    hd->buf[56] = lsb     ;
-    hd->buf[57] = lsb >>  8;
-    hd->buf[58] = lsb >> 16;
-    hd->buf[59] = lsb >> 24;
-    hd->buf[60] = msb     ;
-    hd->buf[61] = msb >>  8;
-    hd->buf[62] = msb >> 16;
-    hd->buf[63] = msb >> 24;
-    transform( hd, hd->buf );
-    burn_stack (108+5*sizeof(void*));
-
-    p = hd->buf;
-  #ifdef BIG_ENDIAN_HOST
-    #define X(a) do { *p++ = hd->h##a     ; *p++ = hd->h##a >> 8;      \
-                     *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
-  #else /* little endian */
-    #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
-  #endif
-    X(0);
-    X(1);
-    X(2);
-    X(3);
-    X(4);
-  #undef X
-}
-
-
-
-/****************
- * Shortcut functions which puts the hash value of the supplied buffer
- * into outbuf which must have a size of 20 bytes.
- */
-void
-rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
-{
-    RMD160_CONTEXT hd;
-
-    rmd160_init( &hd );
-    rmd160_write( &hd, (byte*)buffer, length );
-    rmd160_final( &hd );
-    memcpy( outbuf, hd.buf, 20 );
-}
-
-
-#ifndef __HURD__
-
-static byte *
-rmd160_read( RMD160_CONTEXT *hd )
-{
-    return hd->buf;
-}
-
-/****************
- * Return some information about the algorithm.  We need algo here to
- * distinguish different flavors of the algorithm.
- * Returns: A pointer to string describing the algorithm or NULL if
- *         the ALGO is invalid.
- */
-static const char *
-rmd160_get_info( int algo, size_t *contextsize,
-              byte **r_asnoid, int *r_asnlen, int *r_mdlen,
-              void (**r_init)( void *c ),
-              void (**r_write)( void *c, byte *buf, size_t nbytes ),
-              void (**r_final)( void *c ),
-              byte *(**r_read)( void *c )
-            )
-{
-    static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
-         { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
-           0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
-
-    if( algo != 3 )
-       return NULL;
-
-    *contextsize = sizeof(RMD160_CONTEXT);
-    *r_asnoid = asn;
-    *r_asnlen = DIM(asn);
-    *r_mdlen = 20;
-    *(void  (**)(RMD160_CONTEXT *))r_init                = rmd160_init;
-    *(void  (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
-    *(void  (**)(RMD160_CONTEXT *))r_final               = rmd160_final;
-    *(byte *(**)(RMD160_CONTEXT *))r_read                = rmd160_read;
-
-    return "RIPEMD160";
-}
-
-
-#ifndef IS_MODULE
-static
-#endif
-const char * const gnupgext_version = "RMD160 ($Revision: 1.17.2.4 $)";
-
-static struct {
-    int class;
-    int version;
-    int  value;
-    void (*func)(void);
-} func_table[] = {
-    { 10, 1, 0, (void(*)(void))rmd160_get_info },
-    { 11, 1, 3 },
-};
-
-
-#ifndef IS_MODULE
-static
-#endif
-void *
-gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
-{
-    void *ret;
-    int i = *sequence;
-
-    do {
-       if( i >= DIM(func_table) || i < 0 ) {
-           return NULL;
-       }
-       *class = func_table[i].class;
-       *vers  = func_table[i].version;
-       switch( *class ) {
-         case 11:
-         case 21:
-         case 31:
-           ret = &func_table[i].value;
-           break;
-         default:
-           ret = func_table[i].func;
-           break;
-       }
-       i++;
-    } while( what && what != *class );
-
-    *sequence = i;
-    return ret;
-}
-
-#ifndef IS_MODULE
-void
-rmd160_constructor(void)
-{
-    register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
-}
-#endif
-#endif
diff --git a/random/random.h b/random/random.h
deleted file mode 100644
index a38a417..0000000
--- a/random/random.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* random.c - A single-file translator providing random data
-   Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2, or (at
-   your option) any later version.
-
-   This program 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
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#ifndef __RANDOM_H__
-#define __RANDOM_H__
-
-/* How many random bytes to gather at most.
-   XXX: Should be at least POOLSIZE.  */
-#define GATHERBUFSIZE 32768
-
-/* The random bytes we collected.  */
-extern char gatherbuf[GATHERBUFSIZE];
-
-/* The current positions in gatherbuf[].  */
-extern int gatherrpos;
-extern int gatherwpos;
-
-#endif
diff --git a/sutils/MAKEDEV.sh b/sutils/MAKEDEV.sh
index 1baec15..0730a64 100644
--- a/sutils/MAKEDEV.sh
+++ b/sutils/MAKEDEV.sh
@@ -100,7 +100,7 @@ mkdev() {
        ;;
 
       std)
-       mkdev console tty urandom null zero full fd time mem klog shm
+       mkdev console tty random urandom null zero full fd time mem klog shm
        ;;
       console|com[0-9])
        st $I root 600 /hurd/term ${DEVDIR}/$I device $I;;
@@ -111,8 +111,12 @@ mkdev() {
           ${DEVDIR}/vcs/`echo $I | sed -e s/tty//`/console;;
       lpr[0-9])
         st $I root 660 /hurd/streamio "$I";;
+      random)
+       st $I root 644 /hurd/random --seed-file /var/lib/random-seed;;
       urandom)
-       st $I root 644 /hurd/random --fast --seed-file /var/lib/random-seed;;
+       # Our /dev/random is both secure and non-blocking.  Create a
+       # link for compatibility with Linux.
+       cmd ln -f -s random $I;;
       null)
        st $I root 666 /hurd/null;;
       full)
diff --git a/trans/Makefile b/trans/Makefile
index 65b51d1..a10fa8b 100644
--- a/trans/Makefile
+++ b/trans/Makefile
@@ -21,14 +21,14 @@ makemode := servers
 
 targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
          password hello hello-mt streamio fakeroot proxy-defpager remap \
-         mtab
+         mtab random
 SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
        crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
        fakeroot.c proxy-defpager.c remap.c mtab.c
 OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
        crashServer.o crash_replyUser.o msgServer.o \
        default_pagerServer.o default_pagerUser.o \
-       device_replyServer.o elfcore.o
+       device_replyServer.o elfcore.o startup_notifyServer.o
 HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
 LDLIBS += -lpthread
 password-LDLIBS = -lcrypt
@@ -53,6 +53,8 @@ device_reply-MIGSFLAGS=\
 # libports.  Disable the default payload to port conversion.
 fsys-MIGSFLAGS = "-DHURD_DEFAULT_PAYLOAD_TO_PORT=1"
 
+random-LDLIBS = -lgcrypt
+
 include ../Makeconf
 
 vpath elfcore.c $(top_srcdir)/exec
@@ -64,10 +66,11 @@ password: passwordServer.o
 proxy-defpager: default_pagerServer.o default_pagerUser.o
 streamio: device_replyServer.o
 symlink: fsysServer.o
+random:  startup_notifyServer.o mach_debugUser.o
 
 fakeroot: ../libnetfs/libnetfs.a
 fifo new-fifo: ../libpipe/libpipe.a
-crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password 
proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a
+crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password 
proxy-defpager remap streamio random: ../libtrivfs/libtrivfs.a
 $(targets): ../libfshelp/libfshelp.a \
        ../libihash/libihash.a \
        ../libiohelp/libiohelp.a \
diff --git a/random/random.c b/trans/random.c
similarity index 64%
rename from random/random.c
rename to trans/random.c
index 69176b7..dae2ff4 100644
--- a/random/random.c
+++ b/trans/random.c
@@ -1,5 +1,5 @@
 /* random.c - A single-file translator providing random data
-   Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2001, 2017 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -15,98 +15,266 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#define _GNU_SOURCE 1
-
+#include <argp.h>
+#include <argz.h>
+#include <assert.h>
+#include <error.h>
+#include <fcntl.h>
+#include <gcrypt.h>
 #include <hurd/paths.h>
-#include <hurd/trivfs.h>
 #include <hurd/startup.h>
+#include <hurd/trivfs.h>
+#include <mach/gnumach.h>
+#include <mach/vm_cache_statistics.h>
+#include <mach/vm_param.h>
+#include <mach/vm_statistics.h>
+#include <mach_debug/mach_debug_types.h>
+#include <maptime.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <argp.h>
-#include <argz.h>
-#include <error.h>
 #include <string.h>
-#include <fcntl.h>
 #include <sys/mman.h>
-#include <pthread.h>
-#include <assert.h>
-
+#include <sys/stat.h>
+#include <unistd.h>
 #include <version.h>
 
-#include "random.h"
-#include "gnupg-random.h"
+#include "mach_debug_U.h"
 
-/* Our control port.  */
-struct trivfs_control *fsys;
+
+
+/* Entropy pool.  We use one of the SHAKE algorithms from the Keccak
+   family.  Being a sponge construction, it allows the extraction of
+   arbitrary amounts of pseudorandom data.  */
+static gcry_md_hd_t pool;
+enum gcry_md_algos hash_algo = GCRY_MD_SHAKE128;
 
-int read_blocked;              /* For read and select.  */
-pthread_cond_t wait;           /* For read and select.  */
-pthread_cond_t select_alert;   /* For read and select.  */
+/* Protected by this lock.  */
+static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* A map of the Mach time device.  Used for quick stirring.  */
+volatile struct mapped_time_value *mtime;
+
+static void
+pool_initialize (void)
+{
+  error_t err;
+  gcry_error_t cerr;
+
+  if (! gcry_check_version (GCRYPT_VERSION))
+    error (1, 0, "libgcrypt version mismatch\n");
+
+  cerr = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (cerr)
+    error (1, 0, "Finalizing gcrypt failed: %s",
+          gcry_strerror (cerr));
+
+  cerr = gcry_md_open (&pool, hash_algo, GCRY_MD_FLAG_SECURE);
+  if (cerr)
+    error (1, 0, "Initializing hash failed: %s",
+          gcry_strerror (cerr));
+
+  err = maptime_map (0, NULL, &mtime);
+  if (err)
+    err = maptime_map (1, NULL, &mtime);
+  if (err)
+    error (1, err, "Failed to map time device");
+}
+
+/* Mix data into the pool.  */
+static void
+pool_add_entropy (const void *buffer, size_t length)
+{
+  pthread_mutex_lock (&pool_lock);
+  gcry_md_write (pool, buffer, length);
+  pthread_mutex_unlock (&pool_lock);
+}
+
+/* Extract data from the pool.  */
+static error_t
+pool_randomize (void *buffer, size_t length)
+{
+  gcry_error_t cerr;
+  pthread_mutex_lock (&pool_lock);
+
+  /* Quickly stir the the time device into the pool.  Do not even
+     bother with synchronization.  */
+  gcry_md_write (pool, (void *) mtime, sizeof *mtime);
+
+  cerr = gcry_md_extract (pool, hash_algo, buffer, length);
+  pthread_mutex_unlock (&pool_lock);
+  return cerr ? EIO : 0;
+}
 
 
-/* The quality of randomness we provide.
-   0: Very weak randomness based on time() and getrusage().
-   No external random data is used.
-   1: Pseudo random numbers based on all available real random
-   numbers.
-   2: Strong random numbers with a somewhat guaranteed entropy.
-*/
-#define DEFAULT_LEVEL 2
-static int level = DEFAULT_LEVEL;
 
 /* Name of file to use as seed.  */
 static char *seed_file;
 
-/* The random bytes we collected.  */
-char gatherbuf[GATHERBUFSIZE];
+/* Size of the seed file.  */
+size_t seed_size = 600;
+
+static error_t
+update_random_seed_file (void)
+{
+  error_t err;
+  int fd;
+  void *map;
+
+  if (seed_file == NULL)
+    return 0;
 
-/* The current positions in gatherbuf[].  */
-int gatherrpos;
-int gatherwpos;
+  fd = open (seed_file, O_RDWR|O_CREAT, 0600);
+  if (fd < 0)
+    return errno;
 
-/* XXX Yuk Yuk.  */
-#define POOLSIZE 600
+  if (ftruncate (fd, seed_size))
+    {
+      err = errno;
+      goto out;
+    }
 
-/* Take up to length bytes from gather_random if available.  If
-   nothing is available, sleep until something becomes available.
-   Must be called with global_lock held.  */
-int
-gather_random( void (*add)(const void*, size_t, int), int requester,
-               size_t length, int level )
+  map = mmap (NULL, seed_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+  if (map == MAP_FAILED)
+    {
+      err = errno;
+      goto out;
+    }
+
+  err = pool_randomize (map, seed_size);
+  munmap (map, seed_size);
+
+ out:
+  close (fd);
+  return err;
+}
+
+static error_t
+read_random_seed_file (void)
 {
-  int avail = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
-  int first = GATHERBUFSIZE - gatherrpos;
-  int second = length - first;
+  error_t err;
+  int fd;
+  struct stat s;
+  void *map;
 
-  /* If level is zero, we should not block and not add anything
-     to the pool.  */
-  if( !level )
+  if (seed_file == NULL)
     return 0;
 
-  /* io_read() should guarantee that there is always data available.  */
-  if (level == 2)
-    assert (avail);
+  fd = open (seed_file, O_RDWR);
+  if (fd < 0)
+    return errno;
+
+  if (fstat (fd, &s))
+    {
+      err = errno;
+      goto out;
+    }
+
+  /* XXX should check file permissions.  */
+
+  map = mmap (NULL, s.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+  if (map == MAP_FAILED)
+    {
+      err = errno;
+      goto out;
+    }
+
+  pool_add_entropy (map, s.st_size);
+  /* Immediately update it, to minimize the chance that the same state
+     is read twice.  */
+  pool_randomize (map, s.st_size);
+  munmap (map, s.st_size);
+
+ out:
+  close (fd);
+  return err;
+}
+
+
+
+static void
+gather_slab_info (void)
+{
+  error_t err;
+  cache_info_array_t cache_info;
+  mach_msg_type_number_t cache_info_count;
+
+  cache_info = NULL;
+  cache_info_count = 0;
+
+  err = host_slab_info (mach_host_self(), &cache_info, &cache_info_count);
+  if (err)
+    return;
+
+  pool_add_entropy (cache_info, cache_info_count * sizeof *cache_info);
+
+  vm_deallocate (mach_task_self (),
+                (vm_address_t) cache_info,
+                cache_info_count * sizeof *cache_info);
+}
+
+static void
+gather_vm_statistics (void)
+{
+  error_t err;
+  struct vm_statistics vmstats;
+
+  err = vm_statistics (mach_task_self (), &vmstats);
+  if (err)
+    return;
+
+  pool_add_entropy (&vmstats, sizeof vmstats);
+}
 
-  if (length > avail)
-    length = avail;
+static void
+gather_vm_cache_statistics (void)
+{
+  error_t err;
+  struct vm_cache_statistics cache_stats;
 
-  if (first > length)
-    first = length;
-  (*add) (&gatherbuf[gatherrpos], first, requester);
-  gatherrpos = (gatherrpos + first) % GATHERBUFSIZE;
-  if (second > 0)
+  err = vm_cache_statistics (mach_task_self (), &cache_stats);
+  if (err)
+    return;
+
+  pool_add_entropy (&cache_stats, sizeof cache_stats);
+}
+
+static void *
+gather_thread (void *args)
+{
+  while (1)
     {
-      (*add) (&gatherbuf[gatherrpos], second, requester);
-      gatherrpos += second;
+      gather_slab_info ();
+      gather_vm_statistics ();
+      gather_vm_cache_statistics ();
+      usleep (
+        (useconds_t) (1000000. * (1.
+                                  + (float) random () / (float) RAND_MAX)));
     }
-  return length;
+
+  assert (! "reached");
+}
+
+error_t
+start_gather_thread (void)
+{
+  error_t err;
+  pthread_t thread;
+
+  err = pthread_create (&thread, NULL, gather_thread, NULL);
+  if (err)
+    return err;
+
+  err = pthread_detach (thread);
+  return err;
 }
 
 
+
 const char *argp_program_version = STANDARD_HURD_VERSION (random);
 
-/* This lock protects the GnuPG code.  */
-static pthread_mutex_t global_lock;
+/* Our control port.  */
+struct trivfs_control *fsys;
 
 /* Trivfs hooks. */
 int trivfs_fstype = FSTYPE_MISC;
@@ -122,7 +290,7 @@ void
 trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
 {
   /* Mark the node as a read-only plain file. */
-  st->st_mode &= ~S_IFMT;
+  st->st_mode &= ~((unsigned) S_IFMT);
   st->st_mode |= (S_IFCHR);
   st->st_size = 0;
 }
@@ -130,7 +298,10 @@ trivfs_modify_stat (struct trivfs_protid *cred, struct 
stat *st)
 error_t
 trivfs_goaway (struct trivfs_control *cntl, int flags)
 {
-  update_random_seed_file ();
+  error_t err;
+  err = update_random_seed_file ();
+  if (err)
+    error (0, err, "Warning: Failed to save random seed to %s", seed_file);
   exit (0);
 }
 
@@ -144,53 +315,24 @@ trivfs_S_io_read (struct trivfs_protid *cred,
                  loff_t offs, mach_msg_type_number_t amount)
 {
   error_t err;
-  mach_msg_type_number_t read_amount = 0;
   void *buf = NULL;
-  size_t length;
+  size_t length = 0;
 
-  /* Deny access if they have bad credentials. */
   if (! cred)
     return EOPNOTSUPP;
   else if (! (cred->po->openmodes & O_READ))
     return EBADF;
 
-  pthread_mutex_lock (&global_lock);
-
-  while (amount > 0)
+  if (amount > 0)
     {
-      mach_msg_type_number_t new_amount;
-      /* XXX: It would be nice to fix readable_pool to work for sizes
-        greater than the POOLSIZE.  Otherwise we risk detecting too
-        late that we run out of entropy and all that entropy is
-        wasted.  */
-      while (readable_pool (amount, level) == 0)
-       {
-         if (cred->po->openmodes & O_NONBLOCK)
-           {
-             pthread_mutex_unlock (&global_lock);
-             err = EWOULDBLOCK;
-             goto errout;
-           }
-         read_blocked = 1;
-         if (pthread_hurd_cond_wait_np (&wait, &global_lock))
-           {
-             pthread_mutex_unlock (&global_lock);
-             err = EINTR;
-             goto errout;
-           }
-         /* See term/users.c for possible race?  */
-       }
-
       /* Possibly allocate a new buffer. */
       if (*data_len < amount)
        {
-         *data = mmap (0, amount, PROT_READ|PROT_WRITE,
-                                      MAP_ANON, 0, 0);
-
+         *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
          if (*data == MAP_FAILED)
            {
-             pthread_mutex_unlock (&global_lock);
-             return errno;
+              err = errno;
+              goto errout;
            }
 
          /* Keep track of our map in case of errors.  */
@@ -200,15 +342,14 @@ trivfs_S_io_read (struct trivfs_protid *cred,
          *data_len = amount;
        }
 
-      new_amount = read_pool (((byte *) *data) + read_amount, amount, level);
-      read_amount += new_amount;
-      amount -= new_amount;
-    }
+      err = pool_randomize (*data, amount);
+      if (err)
+        goto errout;
 
-  /* Set atime, see term/users.c */
+    }
 
-  pthread_mutex_unlock (&global_lock);
-  *data_len = read_amount;
+  *data_len = amount;
+  trivfs_set_atime (fsys);
   return 0;
 
  errout:
@@ -233,33 +374,15 @@ trivfs_S_io_write (struct trivfs_protid *cred,
                    loff_t offset,
                    mach_msg_type_number_t *amount)
 {
-  int i = 0;
   /* Deny access if they have bad credentials. */
   if (! cred)
     return EOPNOTSUPP;
   else if (! (cred->po->openmodes & O_WRITE))
     return EBADF;
 
-  pthread_mutex_lock (&global_lock);
-
-  while (i < datalen)
-    {
-      gatherbuf[gatherwpos] = data[i++];
-      gatherwpos = (gatherwpos + 1) % GATHERBUFSIZE;
-      if (gatherrpos == gatherwpos)
-       /* Overrun.  */
-       gatherrpos = (gatherrpos + 1) % GATHERBUFSIZE;
-    }
+  pool_add_entropy (data, datalen);
   *amount = datalen;
-
-  if (datalen > 0 && read_blocked)
-    {
-      read_blocked = 0;
-      pthread_cond_broadcast (&wait);
-      pthread_cond_broadcast (&select_alert);
-    }
-
-  pthread_mutex_unlock (&global_lock);
+  trivfs_set_mtime (fsys);
   return 0;
 }
 
@@ -277,14 +400,9 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
   else if (! (cred->po->openmodes & O_READ))
     return EBADF;
 
-  pthread_mutex_lock (&global_lock);
-
-  /* XXX: Before initialization, the amount depends on the amount we
-     want to read.  Assume some medium value.  */
-  *amount = readable_pool (POOLSIZE/2, level);
-
-  pthread_mutex_unlock (&global_lock);
-
+  /* We allow an infinite amount of data to be extracted.  We need to
+     return something here, so just go with the page size.  */
+  *amount = PAGE_SIZE;
   return 0;
 }
 
@@ -306,33 +424,9 @@ trivfs_S_io_select (struct trivfs_protid *cred,
   if (*type & ~(SELECT_READ | SELECT_WRITE))
     return EINVAL;
 
-  if (*type == 0)
-    return 0;
-
-  pthread_mutex_lock (&global_lock);
-
-  while (1)
-    {
-      /* XXX Before initialization, readable_pool depends on length.  */
-      int avail = readable_pool (POOLSIZE/2, level);
-
-      if (avail != 0 || *type & SELECT_WRITE)
-       {
-         *type = (avail ? SELECT_READ : 0) | (*type & SELECT_WRITE);
-         pthread_mutex_unlock (&global_lock);
-         return 0;
-       }
-
-      ports_interrupt_self_on_port_death (cred, reply);
-      read_blocked = 1;
-
-      if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
-       {
-         *type = 0;
-         pthread_mutex_unlock (&global_lock);
-         return EINTR;
-       }
-    }
+  /* We allow an infinite amount of data to be extracted and stored.
+     Just return success.  */
+  return 0;
 }
 
 
@@ -455,9 +549,8 @@ random_demuxer (mach_msg_header_t *inp,
 
 static const struct argp_option options[] =
 {
-  {"weak",      'w', 0, 0, "Output weak pseudo random data"},
-  {"fast",     'f', 0, 0, "Output cheap random data fast"},
-  {"secure",    's', 0, 0, "Output cryptographically secure random"},
+  {"fast",     'f', 0, 0, "(ignored)"},
+  {"secure",    's', 0, 0, "(ignored)"},
   {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
   {0}
 };
@@ -474,26 +567,14 @@ parse_opt (int opt, char *arg, struct argp_state *state)
     case ARGP_KEY_ERROR:
       break;
 
-    case 'w':
-      {
-       level = 0;
-       break;
-      }
     case 'f':
-      {
-       level = 1;
-       break;
-      }
     case 's':
-      {
-       level = 2;
-       break;
-      }
+      /* Ignored.  */
+      break;
+
     case 'S':
-      {
-       seed_file = strdup (arg);
-       set_random_seed_file (arg);
-      }
+      seed_file = strdup (arg);
+      break;
     }
   return 0;
 }
@@ -507,24 +588,7 @@ trivfs_append_args (struct trivfs_control *fsys,
   error_t err = 0;
   char *opt;
 
-  pthread_mutex_lock (&global_lock);
-  switch (level)
-    {
-    case 0:
-       opt = "--weak";
-       break;
-
-    case 1:
-       opt = "--fast";
-       break;
-
-    default:
-       opt = "--secure";
-    }
-  if (level != DEFAULT_LEVEL)
-    err = argz_add (argz, argz_len, opt);
-
-  if (!err && seed_file)
+  if (seed_file)
     {
       if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
        err = ENOMEM;
@@ -534,7 +598,6 @@ trivfs_append_args (struct trivfs_control *fsys,
          free (opt);
        }
     }
-  pthread_mutex_unlock (&global_lock);
 
   return err;
 }
@@ -554,20 +617,26 @@ struct port_class *shutdown_notify_class;
 error_t
 S_startup_dosync (mach_port_t handle)
 {
+  error_t err;
   struct port_info *inpi = ports_lookup_port (fsys->pi.bucket, handle,
                                              shutdown_notify_class);
 
   if (!inpi)
     return EOPNOTSUPP;
 
-  update_random_seed_file ();
+  err = update_random_seed_file ();
+  if (err)
+    error (0, err, "Warning: Failed to save random seed to %s", seed_file);
   return 0;
 }
 
 void
 sigterm_handler (int signo)
 {
-  update_random_seed_file ();
+  error_t err;
+  err = update_random_seed_file ();
+  if (err)
+    error (0, err, "Warning: Failed to save random seed to %s", seed_file);
   signal (SIGTERM, SIG_DFL);
   raise (SIGTERM);
 }
@@ -581,7 +650,8 @@ arrange_shutdown_notification ()
 
   shutdown_notify_class = ports_create_class (0, 0);
 
-  signal (SIGTERM, sigterm_handler);
+  if (signal (SIGTERM, sigterm_handler) == SIG_ERR)
+    return errno;
 
   /* Arrange to get notified when the system goes down,
      but if we fail for some reason, just silently give up.  No big deal. */
@@ -606,27 +676,27 @@ arrange_shutdown_notification ()
   return err;
 }
 
-
 int
 main (int argc, char **argv)
 {
   error_t err;
+  unsigned int seed;
   mach_port_t bootstrap;
 
-  /* Initialize the lock that will protect everything.
-     We must do this before argp_parse, because parse_opt (above) will
-     use the lock.  */
-  pthread_mutex_init (&global_lock, NULL);
-
-  /* The conditions are used to implement proper read/select
-     behaviour.  */
-  pthread_cond_init (&wait, NULL);
-  pthread_cond_init (&select_alert, NULL);
-
   /* We use the same argp for options available at startup
      as for options we'll accept in an fsys_set_options RPC.  */
   argp_parse (&random_argp, argc, argv, 0, 0, 0);
 
+  pool_initialize ();
+
+  err = read_random_seed_file ();
+  if (err)
+    error (0, err, "Warning: Failed to read random seed file %s", seed_file);
+
+  /* Initialize the libcs PRNG.  */
+  pool_randomize (&seed, sizeof seed);
+  srandom (seed);
+
   task_get_bootstrap_port (mach_task_self (), &bootstrap);
   if (bootstrap == MACH_PORT_NULL)
     error (1, 0, "Must be started as a translator");
@@ -639,7 +709,11 @@ main (int argc, char **argv)
 
   err = arrange_shutdown_notification ();
   if (err)
-    error (0, err, "Warning: cannot request shutdown notification");
+    error (0, err, "Warning: Cannot request shutdown notification");
+
+  err = start_gather_thread ();
+  if (err)
+    error (1, err, "Starting gather thread failed");
 
   /* Launch. */
   ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

[Prev in Thread] Current Thread [Next in Thread]