summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--random/Makefile31
-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.c810
-rw-r--r--random/gnupg-random.h47
-rw-r--r--random/gnupg-rmd.h38
-rw-r--r--random/gnupg-rmd160.c656
-rw-r--r--random/mig-decls.h47
-rw-r--r--random/mig-mutate.h25
-rw-r--r--random/random.c634
-rw-r--r--random/random.h32
12 files changed, 2412 insertions, 0 deletions
diff --git a/random/Makefile b/random/Makefile
new file mode 100644
index 00000000..6291da0c
--- /dev/null
+++ b/random/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 shouldbeinlibc
+OTHERLIBS = -lpthread
+MIGSFLAGS = -DSEQNOS -imacros $(srcdir)/mig-mutate.h
+
+include ../Makeconf
diff --git a/random/TODO b/random/TODO
new file mode 100644
index 00000000..9cc57ab9
--- /dev/null
+++ b/random/TODO
@@ -0,0 +1,11 @@
+* 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
new file mode 100644
index 00000000..188db168
--- /dev/null
+++ b/random/gnupg-bithelp.h
@@ -0,0 +1,41 @@
+/* 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
new file mode 100644
index 00000000..cbf0a103
--- /dev/null
+++ b/random/gnupg-glue.h
@@ -0,0 +1,40 @@
+#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
new file mode 100644
index 00000000..8f308621
--- /dev/null
+++ b/random/gnupg-random.c
@@ -0,0 +1,810 @@
+/* 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 char *rndpool; /* allocated size is POOLSIZE+BLOCKLEN */
+static char *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 )
+{
+ char *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)
+{
+ char *hashbuf = pool + POOLSIZE;
+ char *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
+ /* loop over the pool */
+ pend = pool + POOLSIZE;
+ memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
+ memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+ rmd160_mixblock( &md, hashbuf);
+ memcpy(pool, hashbuf, 20 );
+
+ p = pool;
+ for( n=1; n < POOLBLOCKS; n++ ) {
+ memcpy(hashbuf, p, DIGESTLEN );
+
+ p += DIGESTLEN;
+ if( p+DIGESTLEN+BLOCKLEN < pend )
+ memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+ else {
+ char *pp = p+DIGESTLEN;
+ for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
+ if( pp >= pend )
+ pp = pool;
+ hashbuf[i] = *pp++;
+ }
+ }
+
+ rmd160_mixblock( &md, hashbuf);
+ memcpy(p, hashbuf, 20 );
+ }
+ 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;
+ unsigned char 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 readpoiter to read from a different postion 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 availabe on all systems - so
+ * we better do it just in case one of the above functions
+ * didn't work */
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 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
new file mode 100644
index 00000000..ee18febc
--- /dev/null
+++ b/random/gnupg-random.h
@@ -0,0 +1,47 @@
+/* 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
new file mode 100644
index 00000000..2446fc7d
--- /dev/null
+++ b/random/gnupg-rmd.h
@@ -0,0 +1,38 @@
+/* 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, char *buffer );
+
+#endif /*G10_RMD_H*/
diff --git a/random/gnupg-rmd160.c b/random/gnupg-rmd160.c
new file mode 100644
index 00000000..66107685
--- /dev/null
+++ b/random/gnupg-rmd160.c
@@ -0,0 +1,656 @@
+/* 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, char *buffer )
+{
+ char *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
+}
+
+static byte *
+rmd160_read( RMD160_CONTEXT *hd )
+{
+ return hd->buf;
+}
+
+
+
+/****************
+ * 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 );
+}
+
+
+/****************
+ * 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 __HURD__
+#ifndef IS_MODULE
+void
+rmd160_constructor(void)
+{
+ register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
+}
+#endif
+#endif
diff --git a/random/mig-decls.h b/random/mig-decls.h
new file mode 100644
index 00000000..87b7eb2a
--- /dev/null
+++ b/random/mig-decls.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Justus Winter.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __RANDOM_MIG_DECLS_H__
+#define __RANDOM_MIG_DECLS_H__
+
+#include <hurd/ports.h>
+
+typedef struct port_info *port_info_t;
+
+extern struct trivfs_control *fsys;
+extern struct port_class *shutdown_notify_class;
+
+/* Called by server stub functions. */
+
+static inline struct port_info * __attribute__ ((unused))
+begin_using_startup_port (mach_port_t port)
+{
+ return ports_lookup_port (fsys->pi.bucket,
+ handle,
+ shutdown_notify_class);
+}
+
+static inline void __attribute__ ((unused))
+end_using_startup (struct port_info *p)
+{
+ if (p)
+ ports_port_deref (p);
+}
+
+#endif /* __RANDOM_MIG_DECLS_H__ */
diff --git a/random/mig-mutate.h b/random/mig-mutate.h
new file mode 100644
index 00000000..dab89e56
--- /dev/null
+++ b/random/mig-mutate.h
@@ -0,0 +1,25 @@
+/*
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Justus Winter.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#define STARTUP_INTRAN \
+ port_info_t begin_using_startup_port (mach_port_t)
+#define STARTUP_DESTRUCTOR \
+ end_using_startup (port_info_t)
+#define STARTUP_IMPORTS \
+ import "mig-decls.h";
diff --git a/random/random.c b/random/random.c
new file mode 100644
index 00000000..6eea3631
--- /dev/null
+++ b/random/random.c
@@ -0,0 +1,634 @@
+/* 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 */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <hurd/startup.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 <version.h>
+
+#include "random.h"
+#include "gnupg-random.h"
+
+/* Our control port. */
+struct trivfs_control *fsys;
+
+int read_blocked; /* For read and select. */
+pthread_cond_t wait; /* For read and select. */
+pthread_cond_t select_alert; /* For read and select. */
+
+
+/* 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];
+
+/* The current positions in gatherbuf[]. */
+int gatherrpos;
+int gatherwpos;
+
+/* XXX Yuk Yuk. */
+#define POOLSIZE 600
+
+/* 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 )
+{
+ int avail = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
+ int first = GATHERBUFSIZE - gatherrpos;
+ int second = length - first;
+
+ /* If level is zero, we should not block and not add anything
+ to the pool. */
+ if( !level )
+ return 0;
+
+ /* io_read() should guarantee that there is always data available. */
+ if (level == 2)
+ assert (avail);
+
+ if (length > avail)
+ length = avail;
+
+ if (first > length)
+ first = length;
+ (*add) (&gatherbuf[gatherrpos], first, requester);
+ gatherrpos = (gatherrpos + first) % GATHERBUFSIZE;
+ if (second > 0)
+ {
+ (*add) (&gatherbuf[gatherrpos], second, requester);
+ gatherrpos += second;
+ }
+ return length;
+}
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (random);
+
+/* This lock protects the GnuPG code. */
+static pthread_mutex_t global_lock;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+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 |= (S_IFCHR);
+ st->st_size = 0;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ update_random_seed_file ();
+ exit (0);
+}
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ data_t *data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ /* 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);
+
+ if (amount > 0)
+ {
+ mach_msg_type_number_t new_amount;
+ while (readable_pool (amount, level) == 0)
+ {
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ pthread_mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+ read_blocked = 1;
+ if (pthread_hurd_cond_wait_np (&wait, &global_lock))
+ {
+ pthread_mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ /* 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);
+ if (*data == MAP_FAILED)
+ {
+ pthread_mutex_unlock (&global_lock);
+ return errno;
+ }
+ }
+
+ new_amount = read_pool ((byte *) *data, amount, level);
+
+ if (new_amount < amount)
+ munmap (*data + round_page (new_amount),
+ round_page(amount) - round_page (new_amount));
+ amount = new_amount;
+ }
+ *data_len = amount;
+
+ /* Set atime, see term/users.c */
+
+ pthread_mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they receive more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ data_t data,
+ mach_msg_type_number_t datalen,
+ 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;
+ }
+ *amount = datalen;
+
+ if (datalen > 0 && read_blocked)
+ {
+ read_blocked = 0;
+ pthread_cond_broadcast (&wait);
+ pthread_cond_broadcast (&select_alert);
+ }
+
+ pthread_mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t *amount)
+{
+ /* 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);
+
+ /* 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);
+
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ /* We only deal with SELECT_READ and SELECT_WRITE here. */
+ 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;
+ }
+ }
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ loff_t offs, int whence, loff_t *new_offs)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Not seekable. */
+ return ESPIPE;
+}
+
+/* Change the size of the file. If the size increases, new blocks are
+ zero-filled. After successful return, it is safe to reference mapped
+ areas of the file up to NEW_SIZE. */
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ loff_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map(struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ mach_port_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+
+int
+random_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (trivfs_demuxer (inp, outp)
+ || startup_notify_server (inp, outp));
+}
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+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"},
+ {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'w':
+ {
+ level = 0;
+ break;
+ }
+ case 'f':
+ {
+ level = 1;
+ break;
+ }
+ case 's':
+ {
+ level = 2;
+ break;
+ }
+ case 'S':
+ {
+ seed_file = strdup (arg);
+ set_random_seed_file (arg);
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ 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";
+ break;
+ }
+ }
+ if (level != DEFAULT_LEVEL)
+ err = argz_add (argz, argz_len, opt);
+
+ if (!err && seed_file)
+ {
+ if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
+ err = ENOMEM;
+ else
+ {
+ err = argz_add (argz, argz_len, opt);
+ free (opt);
+ }
+ }
+ pthread_mutex_unlock (&global_lock);
+
+ return err;
+}
+
+static struct argp random_argp =
+{ options, parse_opt, 0,
+ "A translator providing random output." };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &random_argp;
+
+struct port_class *shutdown_notify_class;
+
+/* The system is going down; destroy all the extant port rights. That
+ will cause net channels and such to close promptly. */
+error_t
+S_startup_dosync (struct port_info *inpi)
+{
+ if (!inpi)
+ return EOPNOTSUPP;
+
+ update_random_seed_file ();
+ return 0;
+}
+
+void
+sigterm_handler (int signo)
+{
+ update_random_seed_file ();
+ signal (SIGTERM, SIG_DFL);
+ raise (SIGTERM);
+}
+
+void
+arrange_shutdown_notification ()
+{
+ error_t err;
+ mach_port_t initport, notify;
+ process_t procserver;
+ struct port_info *pi;
+
+ shutdown_notify_class = ports_create_class (0, 0);
+
+ signal (SIGTERM, sigterm_handler);
+
+ /* Arrange to get notified when the system goes down,
+ but if we fail for some reason, just silently give up. No big deal. */
+
+ err = ports_create_port (shutdown_notify_class, fsys->pi.bucket,
+ sizeof (struct port_info), &pi);
+ if (err)
+ return;
+
+ procserver = getproc ();
+ if (!procserver)
+ return;
+
+ err = proc_getmsgport (procserver, 1, &initport);
+ mach_port_deallocate (mach_task_self (), procserver);
+ if (err)
+ return;
+
+ notify = ports_get_send_right (pi);
+ ports_port_deref (pi);
+ startup_request_notification (initport, notify,
+ MACH_MSG_TYPE_MAKE_SEND,
+ program_invocation_short_name);
+ mach_port_deallocate (mach_task_self (), notify);
+ mach_port_deallocate (mach_task_self (), initport);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ 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);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ arrange_shutdown_notification ();
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,
+ 10 * 1000, /* idle thread */
+ 10 * 60 * 1000, /* idle server */
+ 0);
+ return 0;
+}
diff --git a/random/random.h b/random/random.h
new file mode 100644
index 00000000..a38a4177
--- /dev/null
+++ b/random/random.h
@@ -0,0 +1,32 @@
+/* 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