diff options
author | Justus Winter <justus@gnupg.org> | 2017-06-02 00:47:07 +0200 |
---|---|---|
committer | Justus Winter <justus@gnupg.org> | 2017-06-03 16:17:08 +0200 |
commit | 29ff193d27436e52d8112903c882ebe52f071d88 (patch) | |
tree | 0a2b3b6ec7b0ce0d1ebbbd8db7508f7cb7bd7e42 | |
parent | ce6764db1e045421fc9a199a334f63318d9f79d2 (diff) | |
download | hurd-29ff193d27436e52d8112903c882ebe52f071d88.tar.gz hurd-29ff193d27436e52d8112903c882ebe52f071d88.tar.bz2 hurd-29ff193d27436e52d8112903c882ebe52f071d88.zip |
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-- | Makefile | 1 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | random/Makefile | 30 | ||||
-rw-r--r-- | random/TODO | 11 | ||||
-rw-r--r-- | random/gnupg-bithelp.h | 41 | ||||
-rw-r--r-- | random/gnupg-glue.h | 40 | ||||
-rw-r--r-- | random/gnupg-random.c | 809 | ||||
-rw-r--r-- | random/gnupg-random.h | 47 | ||||
-rw-r--r-- | random/gnupg-rmd.h | 38 | ||||
-rw-r--r-- | random/gnupg-rmd160.c | 655 | ||||
-rw-r--r-- | random/random.h | 32 | ||||
-rw-r--r-- | sutils/MAKEDEV.sh | 8 | ||||
-rw-r--r-- | trans/Makefile | 9 | ||||
-rw-r--r-- | trans/random.c (renamed from random/random.c) | 500 |
14 files changed, 303 insertions, 1922 deletions
@@ -40,7 +40,6 @@ prog-subdirs = auth proc exec term \ hostmux usermux ftpfs trans \ console-client utils sutils \ benchmarks fstests \ - random \ procfs \ startup \ init \ @@ -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, |