/[winpt]/trunk/Gnupg/random.c
ViewVC logotype

Diff of /trunk/Gnupg/random.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 46 by werner, Fri Oct 28 12:57:05 2005 UTC
# Line 1  Line 1 
1  /* random.c  - random number generator  /* random.c  - random number generator
2   *      Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.   *      Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
3   *      Copyright (C) 2001, 2002, 2003 Timo Schulz   *      Copyright (C) 2001, 2002, 2003 Timo Schulz
4   *   *
5   * This file is part of GPGLIB.   * This file is part of GPGLIB.
6   *   *
7   * GPGLIB is free software; you can redistribute it and/or modify   * GPGLIB is free software; you can redistribute it and/or modify
8   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
9   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.   * (at your option) any later version.
11   *   *
12   * GPGLIB is distributed in the hope that it will be useful,   * GPGLIB is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.   * GNU General Public License for more details.
16   *   *
17   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
18   * along with GPGLIB; if not, write to the Free Software Foundation,   * along with GPGLIB; if not, write to the Free Software Foundation,
19   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20   *   *
21   * ChangeLog:   * ChangeLog:
22   *   *
23   * - Heavily modified to get rid of the log_xxx functions and other stuff   * - Heavily modified to get rid of the log_xxx functions and other stuff
24   *   that uses the console.   *   that uses the console.
25   * - Applied the XOR bug fix -ts 2002   * - Applied the XOR bug fix -ts 2002
26   * - Removed Libgcrypt malloc stubs and use malloc, calloc and friends directly.   * - Removed Libgcrypt malloc stubs and use malloc, calloc and friends directly.
27   */   */
28    
29  /****************  /****************
30   * This random number generator is modelled after the one described   * This random number generator is modelled after the one described
31   * in Peter Gutmann's Paper: "Software Generation of Practically   * in Peter Gutmann's Paper: "Software Generation of Practically
32   * Strong Random Numbers".   * Strong Random Numbers".
33   */   */
34    
35  #include <windows.h>  #ifdef HAVE_CONFIG_H
36  #include <stdio.h>  #include <config.h>
37  #include <stdlib.h>  #endif
38  #include <assert.h>  
39  #include <errno.h>  #include <windows.h>
40  #include <string.h>  #include <windows.h>
41  #include <sys/types.h>  #include <stdio.h>
42  #include <sys/stat.h>  #include <stdlib.h>
43  #include <time.h>  #include <assert.h>
44  #include <process.h>  #include <errno.h>
45    #include <string.h>
46  #include "openpgp.h"  #include <sys/types.h>
47  #include "md.h"  #include <sys/stat.h>
48    #include <time.h>
49    #include <process.h>
50  int gather_random_fast( void (*add)(const void*, size_t, int), int requester );  #include <ctype.h>
51    
52  void _gpg_secure_random_alloc( void );  #include "openpgp.h"
53  int  _gpg_quick_random_gen( int onoff );  #include "md.h"
54  int  _gpg_random_is_faked(void);  
55  byte *_gpg_get_random_bits( size_t nbits, int level, int secure );  
56  void _gpg_fast_random_poll( void );  int gather_random_fast( void (*add)(const void*, size_t, int), int requester );
57  int gather_random( void (*add)(const void*, size_t, int), int requester,  
58                    size_t length, int level );  void _gpg_secure_random_alloc( void );
59    int  _gpg_quick_random_gen( int onoff );
60  #define fast_random_poll() _gpg_fast_random_poll ()  int  _gpg_random_is_faked(void);
61    byte *_gpg_get_random_bits( size_t nbits, int level, int secure );
62  #define SIZEOF_UNSIGNED_LONG 4  void _gpg_fast_random_poll( void );
63    int gather_random( void (*add)(const void*, size_t, int), int requester,
64  #if SIZEOF_UNSIGNED_LONG == 8                    size_t length, int level );
65    #define ADD_VALUE 0xa5a5a5a5a5a5a5a5  
66  #elif SIZEOF_UNSIGNED_LONG == 4  #define fast_random_poll() _gpg_fast_random_poll ()
67    #define ADD_VALUE 0xa5a5a5a5  
68  #else  #define SIZEOF_UNSIGNED_LONG 4
69    #error "weird size for an unsigned long"  
70  #endif  #if SIZEOF_UNSIGNED_LONG == 8
71      #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
72  #define BLOCKLEN  64   /* hash this amount of bytes */  #elif SIZEOF_UNSIGNED_LONG == 4
73  #define DIGESTLEN 20   /* into a digest of this length (rmd160) */    #define ADD_VALUE 0xa5a5a5a5
74  /* poolblocks is the number of digests which make up the pool  #else
75   * and poolsize must be a multiple of the digest length    #error "weird size for an unsigned long"
76   * to make the AND operations faster, the size should also be  #endif
77   * a multiple of u32  
78   */  #define BLOCKLEN  64   /* hash this amount of bytes */
79  #define POOLBLOCKS 30  #define DIGESTLEN 20   /* into a digest of this length (rmd160) */
80  #define POOLSIZE (POOLBLOCKS*DIGESTLEN)  /* poolblocks is the number of digests which make up the pool
81  #if (POOLSIZE % SIZEOF_UNSIGNED_LONG)   * and poolsize must be a multiple of the digest length
82    #error Please make sure that poolsize is a multiple of u32   * to make the AND operations faster, the size should also be
83  #endif   * a multiple of u32
84  #define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)   */
85    #define POOLBLOCKS 30
86    #define POOLSIZE (POOLBLOCKS*DIGESTLEN)
87  static int is_initialized;  #if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
88  #define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)    #error Please make sure that poolsize is a multiple of u32
89  static char *rndpool;   /* allocated size is POOLSIZE+BLOCKLEN */  #endif
90  static char *keypool;   /* allocated size is POOLSIZE+BLOCKLEN */  #define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
91  static size_t pool_readpos;  
92  static size_t pool_writepos;  
93  static int pool_filled;  static int is_initialized;
94  static int pool_balance;  #define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
95  static int just_mixed;  static char *rndpool;   /* allocated size is POOLSIZE+BLOCKLEN */
96  static int did_initial_extra_seeding;  static char *keypool;   /* allocated size is POOLSIZE+BLOCKLEN */
97  static char *seed_file_name;  static size_t pool_readpos;
98  static int allow_seed_file_update;  static size_t pool_writepos;
99    static int pool_filled;
100  static int secure_alloc;  static int pool_balance;
101  static int quick_test;  static int just_mixed;
102  static int faked_rng;  static int did_initial_extra_seeding;
103    static char *seed_file_name;
104    static int allow_seed_file_update;
105  static byte *get_random_bytes( size_t nbytes, int level, int secure );  
106  static void read_pool( byte *buffer, size_t length, int level );  static int secure_alloc;
107  static void add_randomness( const void *buffer, size_t length, int source );  static int quick_test;
108  static void random_poll(void);  static int faked_rng;
109  static void read_random_source( int requester, size_t length, int level);  
110  static int gather_faked( void (*add)(const void*, size_t, int), int requester,  
111                                                      size_t length, int level );  static byte *get_random_bytes( size_t nbytes, int level, int secure );
112    static void read_pool( byte *buffer, size_t length, int level );
113  static struct {  static void add_randomness( const void *buffer, size_t length, int source );
114      u32 mixrnd;  static void random_poll(void);
115      u32 mixkey;  static void read_random_source( int requester, size_t length, int level);
116      u32 slowpolls;  static int gather_faked( void (*add)(const void*, size_t, int), int requester,
117      u32 fastpolls;                                                      size_t length, int level );
118      u32 getbytes1;  
119      u32 ngetbytes1;  static struct {
120      u32 getbytes2;      u32 mixrnd;
121      u32 ngetbytes2;      u32 mixkey;
122      u32 addbytes;      u32 slowpolls;
123      u32 naddbytes;      u32 fastpolls;
124  } rndstats;      u32 getbytes1;
125        u32 ngetbytes1;
126  static void      u32 getbytes2;
127  initialize(void)      u32 ngetbytes2;
128  {      u32 addbytes;
129      /* The data buffer is allocated somewhat larger, so that      u32 naddbytes;
130       * we can use this extra space (which is allocated in secure memory)  } rndstats;
131       * as a temporary hash buffer */  
132      rndpool = secure_alloc ? calloc(1,POOLSIZE+BLOCKLEN)  static void
133                             : calloc(1,POOLSIZE+BLOCKLEN);  initialize(void)
134      keypool = secure_alloc ? calloc(1,POOLSIZE+BLOCKLEN)  {
135                             : calloc(1,POOLSIZE+BLOCKLEN);      /* The data buffer is allocated somewhat larger, so that
136      is_initialized = 1;       * we can use this extra space (which is allocated in secure memory)
137  }       * as a temporary hash buffer */
138        rndpool = secure_alloc ? calloc(1,POOLSIZE+BLOCKLEN)
139  static void                             : calloc(1,POOLSIZE+BLOCKLEN);
140  burn_stack (int bytes)      keypool = secure_alloc ? calloc(1,POOLSIZE+BLOCKLEN)
141  {                             : calloc(1,POOLSIZE+BLOCKLEN);
142      char buf[128];      is_initialized = 1;
143        }
144      memset (buf, 0, sizeof buf);  
145      bytes -= sizeof buf;  static void
146      if (bytes > 0)  burn_stack (int bytes)
147          burn_stack (bytes);  {
148  }      char buf[128];
149        
150  static void      memset (buf, 0, sizeof buf);
151  random_err(const char *format, ...)      bytes -= sizeof buf;
152  {      if (bytes > 0)
153      char log[8192];          burn_stack (bytes);
154      va_list arg_ptr;  }
155    
156      va_start( arg_ptr, format );      static void
157      _vsnprintf( log, sizeof log-1, format, arg_ptr );  random_err(const char *format, ...)
158      MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK );  {
159      va_end( arg_ptr );      char log[8192];
160  } /* random_err */      va_list arg_ptr;
161    
162        va_start( arg_ptr, format );    
163  void      _vsnprintf( log, sizeof log-1, format, arg_ptr );
164  _gpg_secure_random_alloc( void )      MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK );
165  {      va_end( arg_ptr );
166      secure_alloc = 1;  } /* random_err */
167  }  
168    
169    void
170  int  _gpg_secure_random_alloc( void )
171  gpg_quick_random_gen( int onoff )  {
172  {      secure_alloc = 1;
173      int last;  }
174    
175      read_random_source(0,0,0); /* init */  
176      last = quick_test;  int
177      if( onoff != -1 )  gpg_quick_random_gen( int onoff )
178          quick_test = onoff;  {
179      return faked_rng? 1 : last;      int last;
180  }  
181        read_random_source(0,0,0); /* init */
182        last = quick_test;
183  /****************      if( onoff != -1 )
184   * Fill the buffer with LENGTH bytes of cryptographically strong          quick_test = onoff;
185   * random bytes. level 0 is not very strong, 1 is strong enough      return faked_rng? 1 : last;
186   * for most usage, 2 is good for key generation stuff but may be very slow.  }
187   */  
188  void  
189  gpg_randomize( byte *buffer, size_t length, int level )  /****************
190  {   * Fill the buffer with LENGTH bytes of cryptographically strong
191      char *p = get_random_bytes( length, level, 1 );   * random bytes. level 0 is not very strong, 1 is strong enough
192      memcpy( buffer, p, length );   * for most usage, 2 is good for key generation stuff but may be very slow.
193      free(p);   */
194  }  void
195    gpg_randomize( byte *buffer, size_t length, int level )
196    {
197  char      char *p = get_random_bytes( length, level, 1 );
198  gpg_random_char( int level )      memcpy( buffer, p, length );
199  {            free(p);
200      byte c = 0;  }
201    
202      while ( !isalnum( (int)c ) )  
203          gpg_randomize(&c, 1, level);      char
204      return c % 127;  gpg_random_char( int level )
205  }  {      
206        unsigned char c = 0;
207    
208  int      while ( !isalnum ( c ) )
209  _gpg_random_is_faked()          gpg_randomize(&c, 1, level);    
210  {      return c % 127;
211      if( !is_initialized )  }
212                  initialize();  
213      return faked_rng || quick_test;  
214  }  int
215    _gpg_random_is_faked()
216  /****************  {
217   * Return a pointer to a randomized buffer of level 0 and LENGTH bits      if( !is_initialized )
218   * caller must free the buffer.                  initialize();
219   * Note: The returned value is rounded up to bytes.      return faked_rng || quick_test;
220   */  }
221  static byte *  
222  get_random_bytes( size_t nbytes, int level, int secure )  /****************
223  {   * Return a pointer to a randomized buffer of level 0 and LENGTH bits
224      byte *buf, *p;   * caller must free the buffer.
225     * Note: The returned value is rounded up to bytes.
226      if( quick_test && level > 1 )   */
227                  level = 1;  static byte *
228      MASK_LEVEL(level);  get_random_bytes( size_t nbytes, int level, int secure )
229      if( level == 1 ) {  {
230          rndstats.getbytes1 += nbytes;      byte *buf, *p;
231          rndstats.ngetbytes1++;  
232      }      if( quick_test && level > 1 )
233      else if( level >= 2 ) {                  level = 1;
234          rndstats.getbytes2 += nbytes;      MASK_LEVEL(level);
235          rndstats.ngetbytes2++;      if( level == 1 ) {
236      }          rndstats.getbytes1 += nbytes;
237            rndstats.ngetbytes1++;
238      buf = secure && secure_alloc ? malloc( nbytes ) : malloc( nbytes );      }
239      for( p = buf; nbytes > 0; ) {      else if( level >= 2 ) {
240          size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;          rndstats.getbytes2 += nbytes;
241          read_pool( p, n, level );          rndstats.ngetbytes2++;
242          nbytes -= n;      }
243          p += n;  
244      }      buf = secure && secure_alloc ? malloc( nbytes ) : malloc( nbytes );
245      return buf;      for( p = buf; nbytes > 0; ) {
246  }          size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
247            read_pool( p, n, level );
248  void *          nbytes -= n;
249  gpg_random_bytes( size_t nbytes, int level )          p += n;
250  {      }
251      return get_random_bytes( nbytes, level, 0 );      return buf;
252  }  }
253    
254  void *  void *
255  gpg_random_bytes_secure( size_t nbytes, int level )  gpg_random_bytes( size_t nbytes, int level )
256  {  {
257      return get_random_bytes( nbytes, level, 1 );      return get_random_bytes( nbytes, level, 0 );
258  }  }
259    
260    void *
261  /****************  gpg_random_bytes_secure( size_t nbytes, int level )
262   * Mix the pool  {
263   */      return get_random_bytes( nbytes, level, 1 );
264  static void  }
265  mix_pool(byte *pool)  
266  {  
267      char *hashbuf = pool + POOLSIZE;  /****************
268      char *p, *pend;   * Mix the pool
269      int i, n;   */
270      RMD160_CONTEXT md;  static void
271    mix_pool(byte *pool)
272      rmd160_init( &md );  {
273      /* loop over the pool */      char *hashbuf = pool + POOLSIZE;
274      pend = pool + POOLSIZE;      char *p, *pend;
275      memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );      int i, n;
276      memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);      RMD160_CONTEXT md;
277      rmd160_mixblock( &md, hashbuf);  
278      memcpy(pool, hashbuf, 20 );      rmd160_init( &md );
279        /* loop over the pool */
280      p = pool;      pend = pool + POOLSIZE;
281      for( n=1; n < POOLBLOCKS; n++ ) {      memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
282          memcpy(hashbuf, p, DIGESTLEN );      memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
283          p += DIGESTLEN;      rmd160_mixblock( &md, hashbuf);
284          if( p+DIGESTLEN+BLOCKLEN < pend )      memcpy(pool, hashbuf, 20 );
285              memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);  
286          else {      p = pool;
287              char *pp = p+DIGESTLEN;      for( n=1; n < POOLBLOCKS; n++ ) {
288              for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {          memcpy(hashbuf, p, DIGESTLEN );
289                  if( pp >= pend )          p += DIGESTLEN;
290                      pp = pool;          if( p+DIGESTLEN+BLOCKLEN < pend )
291                  hashbuf[i] = *pp++;              memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
292              }          else {
293          }              char *pp = p+DIGESTLEN;
294          rmd160_mixblock( &md, hashbuf);              for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
295          memcpy(p, hashbuf, 20 );                  if( pp >= pend )
296      }                      pp = pool;
297      burn_stack (200); /* for the rmd160_mixblock() */                  hashbuf[i] = *pp++;
298  }              }
299            }
300  void          rmd160_mixblock( &md, hashbuf);
301  _gpg_set_random_seed_file( const char *name )          memcpy(p, hashbuf, 20 );
302  {      }
303      if( seed_file_name )      burn_stack (200); /* for the rmd160_mixblock() */
304          random_err("Ohhh jeee, this is a BUG; File %s, Line %d", __FILE__, __LINE__);  }
305      seed_file_name = strdup( name );  
306  }  void
307    _gpg_set_random_seed_file( const char *name )
308  /****************  {
309   * Read in a seed form the random_seed file      if( seed_file_name )
310   * and return true if this was successful          random_err("Ohhh jeee, this is a BUG; File %s, Line %d", __FILE__, __LINE__);
311   */      seed_file_name = strdup( name );
312  static int  }
313  read_seed_file()  
314  {  /****************
315      int fd;   * Read in a seed form the random_seed file
316      FILE *fp;   * and return true if this was successful
317      struct stat sb;   */
318      unsigned char buffer[POOLSIZE];  static int
319      int n;  read_seed_file (void)
320    {
321      if( !seed_file_name )      int fd;
322          return 0;      FILE *fp;
323          struct stat sb;
324          fp = fopen( seed_file_name, "rb" );          unsigned char buffer[POOLSIZE];
325      if( fp == NULL && errno == ENOENT) {      int n;
326          allow_seed_file_update = 1;  
327          return 0;      if( !seed_file_name )
328      }          return 0;
329      if( fp == NULL ) {    
330          random_err("can't open `%s': %s", seed_file_name, strerror(errno));          fp = fopen( seed_file_name, "rb" );    
331          return 0;      if( fp == NULL && errno == ENOENT) {
332      }          allow_seed_file_update = 1;
333          fd = fileno(fp);          return 0;
334      if( fstat( fd, &sb ) ) {      }
335          random_err("can't stat `%s': %s", seed_file_name, strerror(errno));      if( fp == NULL ) {
336          fclose(fp);          random_err("can't open `%s': %s", seed_file_name, strerror(errno));
337          return 0;          return 0;
338      }      }
339      if( !(sb.st_mode & _S_IFREG) ) {          fd = fileno(fp);
340          fclose(fp);      if( fstat( fd, &sb ) ) {
341          return 0;          random_err("can't stat `%s': %s", seed_file_name, strerror(errno));
342      }          fclose(fp);
343      if( !sb.st_size ) {          return 0;
344          fclose(fp);      }
345          allow_seed_file_update = 1;      if( !(sb.st_mode & _S_IFREG) ) {
346          return 0;          fclose(fp);
347      }          return 0;
348      if( sb.st_size != POOLSIZE ) {      }
349          fclose(fp);      if( !sb.st_size ) {
350          return 0;          fclose(fp);
351      }          allow_seed_file_update = 1;
352      do {          return 0;
353          n = fread( buffer, 1, POOLSIZE, fp );      }
354      } while( n == -1 && errno == EINTR );      if( sb.st_size != POOLSIZE ) {
355      if( n != POOLSIZE ) {          fclose(fp);
356          random_err("can't read `%s': %s", seed_file_name,strerror(errno));          return 0;
357          fclose(fp);      }
358          return 0;      do {
359      }          n = fread( buffer, 1, POOLSIZE, fp );
360      fclose(fp);      } while( n == -1 && errno == EINTR );
361        if( n != POOLSIZE ) {
362      add_randomness( buffer, POOLSIZE, 0 );          random_err("can't read `%s': %s", seed_file_name,strerror(errno));
363      /* add some minor entropy to the pool now (this will also force a mixing) */          fclose(fp);
364      {   int x = getpid();          return 0;
365          add_randomness( &x, sizeof(x), 0 );      }
366      }      fclose(fp);
367      {   time_t x = time(NULL);  
368          add_randomness( &x, sizeof(x), 0 );      add_randomness( buffer, POOLSIZE, 0 );
369      }      /* add some minor entropy to the pool now (this will also force a mixing) */
370      {   clock_t x = clock();      {   int x = getpid();
371          add_randomness( &x, sizeof(x), 0 );          add_randomness( &x, sizeof(x), 0 );
372      }      }
373      /* And read a few bytes from our entropy source.  By using      {   time_t x = time(NULL);
374       * a level of 0 this will not block and might not return anything          add_randomness( &x, sizeof(x), 0 );
375       * with some entropy drivers, however the rndlinux driver will use      }
376       * /dev/urandom and return some stuff - Do not read to much as we      {   clock_t x = clock();
377       * want to be friendly to the scare system entropy resource. */          add_randomness( &x, sizeof(x), 0 );
378      read_random_source( 0, 16, 0 );      }
379        /* And read a few bytes from our entropy source.  By using
380      allow_seed_file_update = 1;       * a level of 0 this will not block and might not return anything
381      return 1;       * with some entropy drivers, however the rndlinux driver will use
382  }       * /dev/urandom and return some stuff - Do not read to much as we
383         * want to be friendly to the scare system entropy resource. */
384  void      read_random_source( 0, 16, 0 );
385  _gpg_update_random_seed_file()  
386  {      allow_seed_file_update = 1;
387      u32 *sp, *dp;      return 1;
388      int i;  }
389          FILE *fp;  
390    void
391      if( !seed_file_name || !is_initialized || !pool_filled )  _gpg_update_random_seed_file (void)
392                  return;  {
393      if( !allow_seed_file_update )      u32 *sp, *dp;
394                  return;      int i;
395            FILE *fp;
396      /* copy the entropy pool to a scratch pool and mix both of them */  
397      for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) {      if( !seed_file_name || !is_initialized || !pool_filled )
398          *dp = *sp + ADD_VALUE;                  return;
399      }      if( !allow_seed_file_update )
400      mix_pool(rndpool); rndstats.mixrnd++;                  return;
401      mix_pool(keypool); rndstats.mixkey++;  
402          /* copy the entropy pool to a scratch pool and mix both of them */
403      fp = fopen( seed_file_name, "w+b");      for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) {
404      if( fp == NULL ) {          *dp = *sp + ADD_VALUE;
405          random_err("can't create `%s': %s\n", seed_file_name, strerror(errno));      }
406          return;      mix_pool(rndpool); rndstats.mixrnd++;
407      }      mix_pool(keypool); rndstats.mixkey++;
408      do {    
409          i = fwrite( keypool, 1, POOLSIZE, fp );      fp = fopen( seed_file_name, "w+b");
410      } while( i == -1 && errno == EINTR );      if( fp == NULL ) {
411      if( i != POOLSIZE ) {          random_err("can't create `%s': %s\n", seed_file_name, strerror(errno));
412          random_err("can't write `%s': %s\n", seed_file_name, strerror(errno));          return;
413      }      }
414      if( fclose(fp) ) {      do {
415          random_err("can't close `%s': %s\n", seed_file_name, strerror(errno));            i = fwrite( keypool, 1, POOLSIZE, fp );
416      }      } while( i == -1 && errno == EINTR );
417  }      if( i != POOLSIZE ) {
418            random_err("can't write `%s': %s\n", seed_file_name, strerror(errno));
419        }
420  static void      if( fclose(fp) ) {
421  read_pool( byte *buffer, size_t length, int level )          random_err("can't close `%s': %s\n", seed_file_name, strerror(errno));  
422  {      }
423      int i;  }
424      u32 *sp, *dp;  
425    
426      if( length >= POOLSIZE ) {  static void
427          random_err("too many random bits requested; the limit is %d\n", POOLSIZE*8-1);  read_pool( byte *buffer, size_t length, int level )
428      }  {
429      if( !pool_filled ) {      int i;
430          if( read_seed_file() )      u32 *sp, *dp;
431              pool_filled = 1;  
432      }      if( length >= POOLSIZE ) {
433            random_err("too many random bits requested; the limit is %d\n", POOLSIZE*8-1);
434      /* For level 2 quality (key generation) we alwas make      }
435       * sure that the pool has been seeded enough initially */      if( !pool_filled ) {
436      if( level == 2 && !did_initial_extra_seeding ) {          if( read_seed_file() )
437          size_t needed;              pool_filled = 1;
438        }
439          pool_balance = 0;  
440          needed = length - pool_balance;      /* For level 2 quality (key generation) we alwas make
441          if( needed < POOLSIZE/2 )       * sure that the pool has been seeded enough initially */
442              needed = POOLSIZE/2;      if( level == 2 && !did_initial_extra_seeding ) {
443          else if( needed > POOLSIZE )          size_t needed;
444              random_err("Ohhh jeee this is a BUG; File %s, Line %d", __FILE__, __LINE__);  
445          read_random_source( 3, needed, 2 );          pool_balance = 0;
446          pool_balance += needed;          needed = length - pool_balance;
447          did_initial_extra_seeding=1;          if( needed < POOLSIZE/2 )
448      }              needed = POOLSIZE/2;
449            else if( needed > POOLSIZE )
450      /* for level 2 make sure that there is enough random in the pool */              random_err("Ohhh jeee this is a BUG; File %s, Line %d", __FILE__, __LINE__);
451      if( level == 2 && pool_balance < length ) {          read_random_source( 3, needed, 2 );
452          size_t needed;          pool_balance += needed;
453            did_initial_extra_seeding=1;
454          if( pool_balance < 0 )      }
455              pool_balance = 0;  
456          needed = length - pool_balance;      /* for level 2 make sure that there is enough random in the pool */
457          if( needed > POOLSIZE )      if( level == 2 && pool_balance < length ) {
458              random_err("Ohhh jeee this is a BUG; File %s, Line %d", __FILE__, __LINE__);          size_t needed;
459          read_random_source( 3, needed, 2 );  
460          pool_balance += needed;          if( pool_balance < 0 )
461      }              pool_balance = 0;
462            needed = length - pool_balance;
463      /* make sure the pool is filled */          if( needed > POOLSIZE )
464      while( !pool_filled )                    random_err("Ohhh jeee this is a BUG; File %s, Line %d", __FILE__, __LINE__);
465          random_poll();          read_random_source( 3, needed, 2 );
466            pool_balance += needed;
467      /* do always a fast random poll */      }
468      fast_random_poll();  
469        /* make sure the pool is filled */
470      if( !level ) { /* no need for cryptographic strong random */      while( !pool_filled )      
471          /* create a new pool */          random_poll();
472          for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool; i < POOLWORDS; i++, dp++, sp++ )  
473              *dp = *sp + ADD_VALUE;      /* do always a fast random poll */
474          /* must mix both pools */      fast_random_poll();
475          mix_pool(rndpool); rndstats.mixrnd++;  
476          mix_pool(keypool); rndstats.mixkey++;      if( !level ) { /* no need for cryptographic strong random */
477          memcpy( buffer, keypool, length );          /* create a new pool */
478      }          for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool; i < POOLWORDS; i++, dp++, sp++ )
479      else {              *dp = *sp + ADD_VALUE;
480          /* mix the pool (if add_randomness() didn't it) */          /* must mix both pools */
481          if( !just_mixed ) {          mix_pool(rndpool); rndstats.mixrnd++;
482              mix_pool(rndpool);          mix_pool(keypool); rndstats.mixkey++;
483              rndstats.mixrnd++;          memcpy( buffer, keypool, length );
484          }      }
485          /* create a new pool */      else {
486          for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool;          /* mix the pool (if add_randomness() didn't it) */
487                                      i < POOLWORDS; i++, dp++, sp++ )          if( !just_mixed ) {
488              *dp = *sp + ADD_VALUE;              mix_pool(rndpool);
489          /* and mix both pools */              rndstats.mixrnd++;
490          mix_pool(rndpool); rndstats.mixrnd++;          }
491          mix_pool(keypool); rndstats.mixkey++;          /* create a new pool */
492          /* read the required data          for(i=0,dp=(u32*)keypool, sp=(u32*)rndpool;
493           * we use a readpoiter to read from a different postion each                                      i < POOLWORDS; i++, dp++, sp++ )
494           * time */              *dp = *sp + ADD_VALUE;
495          while( length-- ) {          /* and mix both pools */
496              *buffer++ = keypool[pool_readpos++];          mix_pool(rndpool); rndstats.mixrnd++;
497              if( pool_readpos >= POOLSIZE )          mix_pool(keypool); rndstats.mixkey++;
498                  pool_readpos = 0;          /* read the required data
499              pool_balance--;           * we use a readpoiter to read from a different postion each
500          }           * time */
501          if( pool_balance < 0 )          while( length-- ) {
502              pool_balance = 0;              *buffer++ = keypool[pool_readpos++];
503          /* and clear the keypool */              if( pool_readpos >= POOLSIZE )
504          memset( keypool, 0, POOLSIZE );                  pool_readpos = 0;
505      }              pool_balance--;
506  }          }
507            if( pool_balance < 0 )
508                pool_balance = 0;
509  /****************          /* and clear the keypool */
510   * Add LENGTH bytes of randomness from buffer to the pool.          memset( keypool, 0, POOLSIZE );
511   * source may be used to specify the randomness source.      }
512   * Source is:  }
513   *      0 - used ony for initialization  
514   *      1 - fast random poll function  
515   *      2 - normal poll function  /****************
516   *      3 - used when level 2 random quality has been requested   * Add LENGTH bytes of randomness from buffer to the pool.
517   *          to do an extra pool seed.   * source may be used to specify the randomness source.
518   */   * Source is:
519  static void   *      0 - used ony for initialization
520  add_randomness( const void *buffer, size_t length, int source )   *      1 - fast random poll function
521  {   *      2 - normal poll function
522      const byte *p = buffer;   *      3 - used when level 2 random quality has been requested
523     *          to do an extra pool seed.
524      if( !is_initialized )   */
525          initialize();  static void
526      rndstats.addbytes += length;  add_randomness( const void *buffer, size_t length, int source )
527      rndstats.naddbytes++;  {
528      while( length-- ) {      const byte *p = buffer;
529          rndpool[pool_writepos++] ^= *p++;  
530          if( pool_writepos >= POOLSIZE ) {      if( !is_initialized )
531              if( source > 1 )          initialize();
532                  pool_filled = 1;      rndstats.addbytes += length;
533              pool_writepos = 0;      rndstats.naddbytes++;
534              mix_pool(rndpool); rndstats.mixrnd++;      while( length-- ) {
535              just_mixed = !length;                rndpool[pool_writepos++] ^= *p++;
536          }          if( pool_writepos >= POOLSIZE ) {
537      }              if( source > 1 )
538  }                  pool_filled = 1;
539                pool_writepos = 0;
540  static void              mix_pool(rndpool); rndstats.mixrnd++;
541  random_poll( void )              just_mixed = !length;      
542  {          }
543      rndstats.slowpolls++;      }
544      read_random_source( 2, POOLSIZE/5, 1 );  }
545  }  
546    static void
547  void  random_poll( void )
548  _gpg_fast_random_poll( void )  {
549  {      rndstats.slowpolls++;
550      static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;      read_random_source( 2, POOLSIZE/5, 1 );
551      static int initialized = 0;  }
552    
553      rndstats.fastpolls++;  void
554      if( !initialized ) {  _gpg_fast_random_poll( void )
555          if( !is_initialized )  {
556              initialize();      static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
557          initialized = 1;      static int initialized = 0;
558          fnc = gather_random_fast;  
559      }      rndstats.fastpolls++;
560      if( fnc ) {      if( !initialized ) {
561          (*fnc)( add_randomness, 1 );          if( !is_initialized )
562          return;              initialize();
563      }          initialized = 1;
564            fnc = gather_random_fast;
565      /* fall back to the generic function */      }
566              if( fnc ) {
567      /* time and clock are availabe on all systems - so          (*fnc)( add_randomness, 1 );
568       * we better do it just in case one of the above functions          return;
569       * didn't work */      }
570      {   time_t x = time(NULL);  
571          add_randomness( &x, sizeof(x), 1 );      /* fall back to the generic function */
572      }        
573      {   clock_t x = clock();      /* time and clock are availabe on all systems - so
574          add_randomness( &x, sizeof(x), 1 );       * we better do it just in case one of the above functions
575      }       * didn't work */
576  }      {   time_t x = time(NULL);
577            add_randomness( &x, sizeof(x), 1 );
578  static void      }
579  read_random_source( int requester, size_t length, int level )      {   clock_t x = clock();
580  {          add_randomness( &x, sizeof(x), 1 );
581      static int (*fnc)(void (*)(const void*, size_t, int), int,      }
582                                                      size_t, int) = NULL;  }
583      if( !fnc ) {  
584          if( !is_initialized )  static void
585              initialize();  read_random_source( int requester, size_t length, int level )
586          fnc = gather_random;  {
587          if( !fnc ) {      static int (*fnc)(void (*)(const void*, size_t, int), int,
588              faked_rng = 1;                                                      size_t, int) = NULL;
589              fnc = gather_faked;      if( !fnc ) {
590          }          if( !is_initialized )
591          if( !requester && !length && !level )              initialize();
592              return; /* init only */          fnc = gather_random;
593      }          if( !fnc ) {
594      if( (*fnc)( add_randomness, requester, length, level ) < 0 )              faked_rng = 1;
595          random_err("No way to gather entropy for the RNG\n");              fnc = gather_faked;
596  }          }
597            if( !requester && !length && !level )
598                return; /* init only */
599  static int      }
600  gather_faked( void (*add)(const void*, size_t, int), int requester,      if( (*fnc)( add_randomness, requester, length, level ) < 0 )
601                                  size_t length, int level )          random_err("No way to gather entropy for the RNG\n");
602  {  }
603      static int initialized=0;  
604      size_t n;  
605      char *buffer, *p;  static int
606    gather_faked( void (*add)(const void*, size_t, int), int requester,
607      if( !initialized ) {                                  size_t length, int level )
608          random_err("WARNING: using insecure random number generator!!\n");  {
609          initialized=1;            static int initialized=0;
610          srand( time(NULL)*getpid());      size_t n;
611      }      char *buffer, *p;
612    
613      p = buffer = malloc( length );      if( !initialized ) {
614      n = length;            random_err("WARNING: using insecure random number generator!!\n");
615      while( n-- )          initialized=1;      
616                  *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);          srand( time(NULL)*getpid());
617      add_randomness( buffer, length, requester );      }
618      free(buffer);  
619      return 0; /* okay */      p = buffer = malloc( length );
620  }      n = length;  
621        while( n-- )
622                    *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
623        add_randomness( buffer, length, requester );
624        free(buffer);
625        return 0; /* okay */
626    }

Legend:
Removed from v.2  
changed lines
  Added in v.46

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26