summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2017-06-02 00:47:07 +0200
committerJustus Winter <justus@gnupg.org>2017-06-03 16:17:08 +0200
commit29ff193d27436e52d8112903c882ebe52f071d88 (patch)
tree0a2b3b6ec7b0ce0d1ebbbd8db7508f7cb7bd7e42
parentce6764db1e045421fc9a199a334f63318d9f79d2 (diff)
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.
-rw-r--r--Makefile1
-rw-r--r--NEWS4
-rw-r--r--random/Makefile30
-rw-r--r--random/TODO11
-rw-r--r--random/gnupg-bithelp.h41
-rw-r--r--random/gnupg-glue.h40
-rw-r--r--random/gnupg-random.c809
-rw-r--r--random/gnupg-random.h47
-rw-r--r--random/gnupg-rmd.h38
-rw-r--r--random/gnupg-rmd160.c655
-rw-r--r--random/random.h32
-rw-r--r--sutils/MAKEDEV.sh8
-rw-r--r--trans/Makefile9
-rw-r--r--trans/random.c (renamed from random/random.c)500
14 files changed, 303 insertions, 1922 deletions
diff --git a/Makefile b/Makefile
index 9de4fa88..119f130b 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 1b500be2..9482185b 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 5f8a62cb..00000000
--- 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 9cc57ab9..00000000
--- 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 188db168..00000000
--- 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 cbf0a103..00000000
--- 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 a4df6947..00000000
--- 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 ee18febc..00000000
--- 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 102624ad..00000000
--- 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 8f4207b3..00000000
--- 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 a38a4177..00000000
--- 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 1baec151..0730a64b 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 65b51d12..a10fa8b9 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
index 69176b7d..dae2ff4b 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,