1 /* random.c - random number generator
2 * Copyright (C) 1998 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
23 * This random number generator is modelled after the one described
24 * in Peter Gutmann's Paper: "Software Generation of Practically
25 * Strong Random Numbers".
36 #include <sys/types.h>
40 #include <sys/times.h>
42 #ifdef HAVE_GETTIMEOFDAY
43 #include <sys/times.h>
46 #include <sys/resource.h>
53 #include "rand-internal.h"
57 #ifndef RAND_MAX /* for SunOS */
58 #define RAND_MAX 32767
62 #if SIZEOF_UNSIGNED_LONG == 8
63 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
64 #elif SIZEOF_UNSIGNED_LONG == 4
65 #define ADD_VALUE 0xa5a5a5a5
67 #error weird size for an unsigned long
70 #define BLOCKLEN 64 /* hash this amount of bytes */
71 #define DIGESTLEN 20 /* into a digest of this length (rmd160) */
72 /* poolblocks is the number of digests which make up the pool
73 * and poolsize must be a multiple of the digest length
74 * to make the AND operations faster, the size should also be
78 #define POOLSIZE (POOLBLOCKS*DIGESTLEN)
79 #if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
80 #error Please make sure that poolsize is a multiple of ulong
82 #define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
85 static int is_initialized;
86 #define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
87 static char *rndpool; /* allocated size is POOLSIZE+BLOCKLEN */
88 static char *keypool; /* allocated size is POOLSIZE+BLOCKLEN */
89 static size_t pool_readpos;
90 static size_t pool_writepos;
91 static int pool_filled;
92 static int pool_balance;
93 static int just_mixed;
95 static int secure_alloc;
96 static int quick_test;
100 static void read_pool( byte *buffer, size_t length, int level );
101 static void add_randomness( const void *buffer, size_t length, int source );
102 static void random_poll(void);
103 static void read_random_source( int requester, size_t length, int level);
104 static int gather_faked( void (*add)(const void*, size_t, int), int requester,
105 size_t length, int level );
111 /* The data buffer is allocated somewhat larger, so that
112 * we can use this extra space (which is allocated in secure memory)
113 * as a temporary hash buffer */
114 rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
115 : m_alloc_clear(POOLSIZE+BLOCKLEN);
116 keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
117 : m_alloc_clear(POOLSIZE+BLOCKLEN);
121 rndlinux_constructor();
123 rndunix_constructor();
132 secure_random_alloc()
139 quick_random_gen( int onoff )
143 read_random_source(0,0,0); /* init */
147 return faked_rng? 1 : last;
152 * Fill the buffer with LENGTH bytes of cryptographically strong
153 * random bytes. level 0 is not very strong, 1 is strong enough
154 * for most usage, 2 is good for key generation stuff but may be very slow.
157 randomize_buffer( byte *buffer, size_t length, int level )
159 char *p = get_random_bits( length*8, level, m_is_secure(buffer) );
160 memcpy( buffer, p, length );
168 if( !is_initialized )
170 return faked_rng || quick_test;
174 * Return a pointer to a randomized buffer of level 0 and LENGTH bits
175 * caller must free the buffer.
176 * Note: The returned value is rounded up to bytes.
179 get_random_bits( size_t nbits, int level, int secure )
182 size_t nbytes = (nbits+7)/8;
184 if( quick_test && level > 1 )
187 buf = secure && secure_alloc ? m_alloc_secure( nbytes ) : m_alloc( nbytes );
188 read_pool( buf, nbytes, level );
199 char *hashbuf = pool + POOLSIZE;
206 #error must have a digest length of 20 for ripe-md-160
208 /* loop over the pool */
209 pend = pool + POOLSIZE;
210 memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
211 memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
212 rmd160_mixblock( &md, hashbuf);
213 memcpy(pool, hashbuf, 20 );
216 for( n=1; n < POOLBLOCKS; n++ ) {
217 memcpy(hashbuf, p, DIGESTLEN );
220 if( p+DIGESTLEN+BLOCKLEN < pend )
221 memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
223 char *pp = p+DIGESTLEN;
224 for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
231 rmd160_mixblock( &md, hashbuf);
232 memcpy(p, hashbuf, 20 );
238 read_pool( byte *buffer, size_t length, int level )
243 if( length >= POOLSIZE )
244 BUG(); /* not allowed */
246 /* for level 2 make sure that there is enough random in the pool */
247 if( level == 2 && pool_balance < length ) {
250 if( pool_balance < 0 )
252 needed = length - pool_balance;
253 if( needed > POOLSIZE )
255 read_random_source( 3, needed, 2 );
256 pool_balance += needed;
259 /* make sure the pool is filled */
260 while( !pool_filled )
263 /* do always a fast random poll */
266 if( !level ) { /* no need for cryptographic strong random */
267 /* create a new pool */
268 for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
269 i < POOLWORDS; i++, dp++, sp++ )
270 *dp = *sp + ADD_VALUE;
271 /* must mix both pools */
274 memcpy( buffer, keypool, length );
277 /* mix the pool (if add_randomness() didn't it) */
280 /* create a new pool */
281 for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
282 i < POOLWORDS; i++, dp++, sp++ )
283 *dp = *sp + ADD_VALUE;
284 /* and mix both pools */
287 /* read the required data
288 * we use a readpoiter to read from a different postion each
291 *buffer++ = keypool[pool_readpos++];
292 if( pool_readpos >= POOLSIZE )
296 if( pool_balance < 0 )
298 /* and clear the keypool */
299 memset( keypool, 0, POOLSIZE );
305 * Add LENGTH bytes of randomness from buffer to the pool.
306 * source may be used to specify the randomness source.
309 add_randomness( const void *buffer, size_t length, int source )
311 if( !is_initialized )
314 rndpool[pool_writepos++] = *((byte*)buffer)++;
315 if( pool_writepos >= POOLSIZE ) {
320 just_mixed = !length;
330 read_random_source( 2, POOLSIZE/5, 1 );
337 static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
338 static int initialized = 0;
341 if( !is_initialized )
344 fnc = dynload_getfnc_fast_random_poll();
347 (*fnc)( add_randomness, 1 );
351 /* fall back to the generic function */
355 add_randomness( &tv, sizeof(tv), 1 );
357 #elif HAVE_GETTIMEOFDAY
359 if( gettimeofday( &tv, NULL ) )
361 add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
362 add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
364 #else /* use times */
367 add_randomness( &buf, sizeof buf, 1 );
370 #ifdef HAVE_GETRUSAGE
372 if( getrusage( RUSAGE_SELF, &buf ) )
374 add_randomness( &buf, sizeof buf, 1 );
375 memset( &buf, 0, sizeof buf );
383 read_random_source( int requester, size_t length, int level )
385 static int (*fnc)(void (*)(const void*, size_t, int), int,
388 if( !is_initialized )
390 fnc = dynload_getfnc_gather_random();
395 if( !requester && !length && !level )
396 return; /* init only */
398 if( (*fnc)( add_randomness, requester, length, level ) < 0 )
399 log_fatal("No way to gather entropy for the RNG\n");
404 gather_faked( void (*add)(const void*, size_t, int), int requester,
405 size_t length, int level )
407 static int initialized=0;
412 log_info(_("WARNING: using insecure random number generator!!\n"));
413 tty_printf(_("The random number generator is only a kludge to let\n"
414 "it run - it is in no way a strong RNG!\n\n"
415 "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
418 srand(make_timestamp()*getpid());
420 srandom(make_timestamp()*getpid());
424 p = buffer = m_alloc( length );
428 *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
431 *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
433 add_randomness( buffer, length, requester );