~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to cipher/random.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* random.c  -  random number generator
 
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 */
 
20
 
 
21
 
 
22
/****************
 
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".
 
26
 */
 
27
 
 
28
 
 
29
#include <config.h>
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <assert.h>
 
33
#include <errno.h>
 
34
#include <string.h>
 
35
#include <time.h>
 
36
#include <sys/time.h>
 
37
#include <sys/types.h>
 
38
#include <sys/stat.h>
 
39
#include <unistd.h>
 
40
#include <fcntl.h>
 
41
#ifdef  HAVE_GETHRTIME
 
42
  #include <sys/times.h>
 
43
#endif
 
44
#ifdef HAVE_GETTIMEOFDAY
 
45
  #include <sys/times.h>
 
46
#endif
 
47
#ifdef HAVE_GETRUSAGE
 
48
  #include <sys/resource.h>
 
49
#endif
 
50
#ifdef __MINGW32__
 
51
  #include <process.h>
 
52
#endif
 
53
#include "util.h"
 
54
#include "rmd.h"
 
55
#include "ttyio.h"
 
56
#include "i18n.h"
 
57
#include "random.h"
 
58
#include "rand-internal.h"
 
59
#include "algorithms.h"
 
60
 
 
61
#ifndef RAND_MAX   /* for SunOS */
 
62
  #define RAND_MAX 32767
 
63
#endif
 
64
 
 
65
 
 
66
#if SIZEOF_UNSIGNED_LONG == 8
 
67
  #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
 
68
#elif SIZEOF_UNSIGNED_LONG == 4
 
69
  #define ADD_VALUE 0xa5a5a5a5
 
70
#else
 
71
  #error weird size for an unsigned long
 
72
#endif
 
73
 
 
74
#define BLOCKLEN  64   /* hash this amount of bytes */
 
75
#define DIGESTLEN 20   /* into a digest of this length (rmd160) */
 
76
/* poolblocks is the number of digests which make up the pool
 
77
 * and poolsize must be a multiple of the digest length
 
78
 * to make the AND operations faster, the size should also be
 
79
 * a multiple of ulong
 
80
 */
 
81
#define POOLBLOCKS 30
 
82
#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
 
83
#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
 
84
  #error Please make sure that poolsize is a multiple of ulong
 
85
#endif
 
86
#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
 
87
 
 
88
 
 
89
static int is_initialized;
 
90
#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
 
91
static char *rndpool;   /* allocated size is POOLSIZE+BLOCKLEN */
 
92
static char *keypool;   /* allocated size is POOLSIZE+BLOCKLEN */
 
93
static size_t pool_readpos;
 
94
static size_t pool_writepos;
 
95
static int pool_filled;
 
96
static int pool_balance;
 
97
static int just_mixed;
 
98
static int did_initial_extra_seeding;
 
99
static char *seed_file_name;
 
100
static int allow_seed_file_update;
 
101
 
 
102
static int secure_alloc;
 
103
static int quick_test;
 
104
static int faked_rng;
 
105
 
 
106
 
 
107
static void read_pool( byte *buffer, size_t length, int level );
 
108
static void add_randomness( const void *buffer, size_t length, int source );
 
109
static void random_poll(void);
 
110
static void read_random_source( int requester, size_t length, int level);
 
111
static int gather_faked( void (*add)(const void*, size_t, int), int requester,
 
112
                                                    size_t length, int level );
 
113
 
 
114
static struct {
 
115
    ulong mixrnd;
 
116
    ulong mixkey;
 
117
    ulong slowpolls;
 
118
    ulong fastpolls;
 
119
    ulong getbytes1;
 
120
    ulong ngetbytes1;
 
121
    ulong getbytes2;
 
122
    ulong ngetbytes2;
 
123
    ulong addbytes;
 
124
    ulong naddbytes;
 
125
} rndstats;
 
126
 
 
127
 
 
128
static int (*
 
129
getfnc_gather_random (void))(void (*)(const void*, size_t, int), int,
 
130
                        size_t, int)
 
131
{
 
132
#ifdef USE_ALL_RANDOM_MODULES
 
133
  static int (*fnc)(void (*)(const void*, size_t, int), int, size_t, int);
 
134
  
 
135
  if (fnc)
 
136
    return fnc;
 
137
# ifdef USE_RNDLINUX
 
138
  if ( !access (NAME_OF_DEV_RANDOM, R_OK)
 
139
       && !access (NAME_OF_DEV_RANDOM, R_OK))
 
140
    {
 
141
      fnc = rndlinux_gather_random;
 
142
      return fnc;
 
143
    }
 
144
# endif
 
145
# ifdef USE_RNDEGD
 
146
  if ( rndegd_connect_socket (1) != -1 )
 
147
    {
 
148
      fnc = rndegd_gather_random;
 
149
      return fnc;
 
150
    }
 
151
# endif
 
152
# ifdef USE_RNDUNIX
 
153
  fnc = rndunix_gather_random;
 
154
  return fnc;
 
155
# endif
 
156
 
 
157
  log_fatal (_("no entropy gathering module detected\n"));
 
158
 
 
159
#else
 
160
# ifdef USE_RNDLINUX
 
161
  return rndlinux_gather_random;
 
162
# endif
 
163
# ifdef USE_RNDUNIX
 
164
  return rndunix_gather_random;
 
165
# endif
 
166
# ifdef USE_RNDEGD
 
167
  return rndegd_gather_random;
 
168
# endif
 
169
# ifdef USE_RNDW32
 
170
  return rndw32_gather_random;
 
171
# endif
 
172
# ifdef USE_RNDRISCOS
 
173
  return rndriscos_gather_random;
 
174
# endif
 
175
#endif
 
176
  return NULL;
 
177
}
 
178
 
 
179
static void (*
 
180
getfnc_fast_random_poll (void))( void (*)(const void*, size_t, int), int)
 
181
{
 
182
#ifdef USE_RNDW32
 
183
  return rndw32_gather_random_fast;
 
184
#endif
 
185
  return NULL;
 
186
}
 
187
 
 
188
 
 
189
 
 
190
static void
 
191
initialize(void)
 
192
{
 
193
    /* The data buffer is allocated somewhat larger, so that
 
194
     * we can use this extra space (which is allocated in secure memory)
 
195
     * as a temporary hash buffer */
 
196
    rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
 
197
                           : m_alloc_clear(POOLSIZE+BLOCKLEN);
 
198
    keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
 
199
                           : m_alloc_clear(POOLSIZE+BLOCKLEN);
 
200
    is_initialized = 1;
 
201
}
 
202
 
 
203
static void
 
204
burn_stack (int bytes)
 
205
{
 
206
    char buf[128];
 
207
    
 
208
    memset (buf, 0, sizeof buf);
 
209
    bytes -= sizeof buf;
 
210
    if (bytes > 0)
 
211
        burn_stack (bytes);
 
212
}
 
213
 
 
214
void
 
215
random_dump_stats()
 
216
{
 
217
    fprintf(stderr,
 
218
            "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
 
219
            "              outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
 
220
        POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
 
221
                  rndstats.naddbytes, rndstats.addbytes,
 
222
        rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
 
223
                    rndstats.ngetbytes2, rndstats.getbytes2 );
 
224
}
 
225
 
 
226
void
 
227
secure_random_alloc()
 
228
{
 
229
    secure_alloc = 1;
 
230
}
 
231
 
 
232
 
 
233
int
 
234
quick_random_gen( int onoff )
 
235
{
 
236
    int last;
 
237
 
 
238
    read_random_source(0,0,0); /* init */
 
239
    last = quick_test;
 
240
    if( onoff != -1 )
 
241
        quick_test = onoff;
 
242
    return faked_rng? 1 : last;
 
243
}
 
244
 
 
245
 
 
246
/****************
 
247
 * Fill the buffer with LENGTH bytes of cryptographically strong
 
248
 * random bytes. level 0 is not very strong, 1 is strong enough
 
249
 * for most usage, 2 is good for key generation stuff but may be very slow.
 
250
 */
 
251
void
 
252
randomize_buffer( byte *buffer, size_t length, int level )
 
253
{
 
254
    char *p = get_random_bits( length*8, level, 1 );
 
255
    memcpy( buffer, p, length );
 
256
    m_free(p);
 
257
}
 
258
 
 
259
 
 
260
int
 
261
random_is_faked()
 
262
{
 
263
    if( !is_initialized )
 
264
        initialize();
 
265
    return faked_rng || quick_test;
 
266
}
 
267
 
 
268
/****************
 
269
 * Return a pointer to a randomized buffer of level 0 and LENGTH bits
 
270
 * caller must free the buffer.
 
271
 * Note: The returned value is rounded up to bytes.
 
272
 */
 
273
byte *
 
274
get_random_bits( size_t nbits, int level, int secure )
 
275
{
 
276
    byte *buf, *p;
 
277
    size_t nbytes = (nbits+7)/8;
 
278
 
 
279
    if( quick_test && level > 1 )
 
280
        level = 1;
 
281
    MASK_LEVEL(level);
 
282
    if( level == 1 ) {
 
283
        rndstats.getbytes1 += nbytes;
 
284
        rndstats.ngetbytes1++;
 
285
    }
 
286
    else if( level >= 2 ) {
 
287
        rndstats.getbytes2 += nbytes;
 
288
        rndstats.ngetbytes2++;
 
289
    }
 
290
 
 
291
    buf = secure && secure_alloc ? m_alloc_secure( nbytes ) : m_alloc( nbytes );
 
292
    for( p = buf; nbytes > 0; ) {
 
293
        size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
 
294
        read_pool( p, n, level );
 
295
        nbytes -= n;
 
296
        p += n;
 
297
    }
 
298
    return buf;
 
299
}
 
300
 
 
301
 
 
302
/****************
 
303
 * Mix the pool
 
304
 */
 
305
static void
 
306
mix_pool(byte *pool)
 
307
{
 
308
    char *hashbuf = pool + POOLSIZE;
 
309
    char *p, *pend;
 
310
    int i, n;
 
311
    RMD160_CONTEXT md;
 
312
 
 
313
    rmd160_init( &md );
 
314
 #if DIGESTLEN != 20
 
315
    #error must have a digest length of 20 for ripe-md-160
 
316
 #endif
 
317
    /* loop over the pool */
 
318
    pend = pool + POOLSIZE;
 
319
    memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
 
320
    memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
 
321
    rmd160_mixblock( &md, hashbuf);
 
322
    memcpy(pool, hashbuf, 20 );
 
323
 
 
324
    p = pool;
 
325
    for( n=1; n < POOLBLOCKS; n++ ) {
 
326
        memcpy(hashbuf, p, DIGESTLEN );
 
327
 
 
328
        p += DIGESTLEN;
 
329
        if( p+DIGESTLEN+BLOCKLEN < pend )
 
330
            memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
 
331
        else {
 
332
            char *pp = p+DIGESTLEN;
 
333
            for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
 
334
                if( pp >= pend )
 
335
                    pp = pool;
 
336
                hashbuf[i] = *pp++;
 
337
            }
 
338
        }
 
339
 
 
340
        rmd160_mixblock( &md, hashbuf);
 
341
        memcpy(p, hashbuf, 20 );
 
342
    }
 
343
    burn_stack (384); /* for the rmd160_mixblock() */
 
344
}
 
345
 
 
346
 
 
347
void
 
348
set_random_seed_file( const char *name )
 
349
{
 
350
    if( seed_file_name )
 
351
        BUG();
 
352
    seed_file_name = m_strdup( name );
 
353
}
 
354
 
 
355
/****************
 
356
 * Read in a seed form the random_seed file
 
357
 * and return true if this was successful
 
358
 */
 
359
static int
 
360
read_seed_file(void)
 
361
{
 
362
    int fd;
 
363
    struct stat sb;
 
364
    unsigned char buffer[POOLSIZE];
 
365
    int n;
 
366
 
 
367
    if( !seed_file_name )
 
368
        return 0;
 
369
 
 
370
  #ifdef HAVE_DOSISH_SYSTEM
 
371
    fd = open( seed_file_name, O_RDONLY | O_BINARY );
 
372
  #else
 
373
    fd = open( seed_file_name, O_RDONLY );
 
374
  #endif
 
375
    if( fd == -1 && errno == ENOENT) {
 
376
        allow_seed_file_update = 1;
 
377
        return 0;
 
378
    }
 
379
 
 
380
    if( fd == -1 ) {
 
381
        log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
 
382
        return 0;
 
383
    }
 
384
    if( fstat( fd, &sb ) ) {
 
385
        log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
 
386
        close(fd);
 
387
        return 0;
 
388
    }
 
389
    if( !S_ISREG(sb.st_mode) ) {
 
390
        log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
 
391
        close(fd);
 
392
        return 0;
 
393
    }
 
394
    if( !sb.st_size ) {
 
395
        log_info(_("note: random_seed file is empty\n") );
 
396
        close(fd);
 
397
        allow_seed_file_update = 1;
 
398
        return 0;
 
399
    }
 
400
    if( sb.st_size != POOLSIZE ) {
 
401
        log_info(_("WARNING: invalid size of random_seed file - not used\n") );
 
402
        close(fd);
 
403
        return 0;
 
404
    }
 
405
    do {
 
406
        n = read( fd, buffer, POOLSIZE );
 
407
    } while( n == -1 && errno == EINTR );
 
408
    if( n != POOLSIZE ) {
 
409
        log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
 
410
        close(fd);
 
411
        return 0;
 
412
    }
 
413
 
 
414
    close(fd);
 
415
 
 
416
    add_randomness( buffer, POOLSIZE, 0 );
 
417
    /* add some minor entropy to the pool now (this will also force a mixing) */
 
418
    {   pid_t x = getpid();
 
419
        add_randomness( &x, sizeof(x), 0 );
 
420
    }
 
421
    {   time_t x = time(NULL);
 
422
        add_randomness( &x, sizeof(x), 0 );
 
423
    }
 
424
    {   clock_t x = clock();
 
425
        add_randomness( &x, sizeof(x), 0 );
 
426
    }
 
427
    /* And read a few bytes from our entropy source.  By using
 
428
     * a level of 0 this will not block and might not return anything
 
429
     * with some entropy drivers, however the rndlinux driver will use
 
430
     * /dev/urandom and return some stuff - Do not read to much as we
 
431
     * want to be friendly to the scare system entropy resource. */
 
432
    read_random_source( 0, 16, 0 );
 
433
 
 
434
    allow_seed_file_update = 1;
 
435
    return 1;
 
436
}
 
437
 
 
438
void
 
439
update_random_seed_file()
 
440
{
 
441
    ulong *sp, *dp;
 
442
    int fd, i;
 
443
 
 
444
    if( !seed_file_name || !is_initialized || !pool_filled )
 
445
        return;
 
446
    if( !allow_seed_file_update ) {
 
447
        log_info(_("note: random_seed file not updated\n"));
 
448
        return;
 
449
    }
 
450
 
 
451
 
 
452
    /* copy the entropy pool to a scratch pool and mix both of them */
 
453
    for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
 
454
                                    i < POOLWORDS; i++, dp++, sp++ ) {
 
455
        *dp = *sp + ADD_VALUE;
 
456
    }
 
457
    mix_pool(rndpool); rndstats.mixrnd++;
 
458
    mix_pool(keypool); rndstats.mixkey++;
 
459
 
 
460
  #ifdef HAVE_DOSISH_SYSTEM
 
461
    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
 
462
                                                        S_IRUSR|S_IWUSR );
 
463
  #else
 
464
    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
 
465
  #endif
 
466
    if( fd == -1 ) {
 
467
        log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
 
468
        return;
 
469
    }
 
470
    do {
 
471
        i = write( fd, keypool, POOLSIZE );
 
472
    } while( i == -1 && errno == EINTR );
 
473
    if( i != POOLSIZE ) {
 
474
        log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
 
475
    }
 
476
    if( close(fd) )
 
477
        log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
 
478
}
 
479
 
 
480
 
 
481
static void
 
482
read_pool( byte *buffer, size_t length, int level )
 
483
{
 
484
    int i;
 
485
    ulong *sp, *dp;
 
486
 
 
487
    if( length > POOLSIZE ) {
 
488
        log_bug("too many random bits requested\n");
 
489
    }
 
490
 
 
491
    if( !pool_filled ) {
 
492
        if( read_seed_file() )
 
493
            pool_filled = 1;
 
494
    }
 
495
 
 
496
    /* For level 2 quality (key generation) we alwas make
 
497
     * sure that the pool has been seeded enough initially */
 
498
    if( level == 2 && !did_initial_extra_seeding ) {
 
499
        size_t needed;
 
500
 
 
501
        pool_balance = 0;
 
502
        needed = length - pool_balance;
 
503
        if( needed < POOLSIZE/2 )
 
504
            needed = POOLSIZE/2;
 
505
        else if( needed > POOLSIZE )
 
506
            BUG();
 
507
        read_random_source( 3, needed, 2 );
 
508
        pool_balance += needed;
 
509
        did_initial_extra_seeding=1;
 
510
    }
 
511
 
 
512
    /* for level 2 make sure that there is enough random in the pool */
 
513
    if( level == 2 && pool_balance < length ) {
 
514
        size_t needed;
 
515
 
 
516
        if( pool_balance < 0 )
 
517
            pool_balance = 0;
 
518
        needed = length - pool_balance;
 
519
        if( needed > POOLSIZE )
 
520
            BUG();
 
521
        read_random_source( 3, needed, 2 );
 
522
        pool_balance += needed;
 
523
    }
 
524
 
 
525
    /* make sure the pool is filled */
 
526
    while( !pool_filled )
 
527
        random_poll();
 
528
 
 
529
    /* do always a fast random poll */
 
530
    fast_random_poll();
 
531
 
 
532
    if( !level ) { /* no need for cryptographic strong random */
 
533
        /* create a new pool */
 
534
        for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
 
535
                                    i < POOLWORDS; i++, dp++, sp++ )
 
536
            *dp = *sp + ADD_VALUE;
 
537
        /* must mix both pools */
 
538
        mix_pool(rndpool); rndstats.mixrnd++;
 
539
        mix_pool(keypool); rndstats.mixkey++;
 
540
        memcpy( buffer, keypool, length );
 
541
    }
 
542
    else {
 
543
        /* mix the pool (if add_randomness() didn't it) */
 
544
        if( !just_mixed ) {
 
545
            mix_pool(rndpool);
 
546
            rndstats.mixrnd++;
 
547
        }
 
548
        /* create a new pool */
 
549
        for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
 
550
                                    i < POOLWORDS; i++, dp++, sp++ )
 
551
            *dp = *sp + ADD_VALUE;
 
552
        /* and mix both pools */
 
553
        mix_pool(rndpool); rndstats.mixrnd++;
 
554
        mix_pool(keypool); rndstats.mixkey++;
 
555
        /* read the required data
 
556
         * we use a readpoiter to read from a different postion each
 
557
         * time */
 
558
        while( length-- ) {
 
559
            *buffer++ = keypool[pool_readpos++];
 
560
            if( pool_readpos >= POOLSIZE )
 
561
                pool_readpos = 0;
 
562
            pool_balance--;
 
563
        }
 
564
        if( pool_balance < 0 )
 
565
            pool_balance = 0;
 
566
        /* and clear the keypool */
 
567
        memset( keypool, 0, POOLSIZE );
 
568
    }
 
569
}
 
570
 
 
571
 
 
572
/****************
 
573
 * Add LENGTH bytes of randomness from buffer to the pool.
 
574
 * source may be used to specify the randomness source.
 
575
 * Source is:
 
576
 *      0 - used ony for initialization
 
577
 *      1 - fast random poll function
 
578
 *      2 - normal poll function
 
579
 *      3 - used when level 2 random quality has been requested
 
580
 *          to do an extra pool seed.
 
581
 */
 
582
static void
 
583
add_randomness( const void *buffer, size_t length, int source )
 
584
{
 
585
    const byte *p = buffer;
 
586
 
 
587
    if( !is_initialized )
 
588
        initialize();
 
589
    rndstats.addbytes += length;
 
590
    rndstats.naddbytes++;
 
591
    while( length-- ) {
 
592
        rndpool[pool_writepos++] ^= *p++;
 
593
        if( pool_writepos >= POOLSIZE ) {
 
594
            if( source > 1 )
 
595
                pool_filled = 1;
 
596
            pool_writepos = 0;
 
597
            mix_pool(rndpool); rndstats.mixrnd++;
 
598
            just_mixed = !length;
 
599
        }
 
600
    }
 
601
}
 
602
 
 
603
 
 
604
 
 
605
static void
 
606
random_poll()
 
607
{
 
608
    rndstats.slowpolls++;
 
609
    read_random_source( 2, POOLSIZE/5, 1 );
 
610
}
 
611
 
 
612
 
 
613
void
 
614
fast_random_poll()
 
615
{
 
616
    static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
 
617
    static int initialized = 0;
 
618
 
 
619
    rndstats.fastpolls++;
 
620
    if( !initialized ) {
 
621
        if( !is_initialized )
 
622
            initialize();
 
623
        initialized = 1;
 
624
        fnc = getfnc_fast_random_poll();
 
625
    }
 
626
    if( fnc ) {
 
627
        (*fnc)( add_randomness, 1 );
 
628
        return;
 
629
    }
 
630
 
 
631
    /* fall back to the generic function */
 
632
  #if defined(HAVE_GETHRTIME) && !defined(HAVE_BROKEN_GETHRTIME)
 
633
    {   hrtime_t tv;
 
634
        /* On some Solaris and HPUX system gethrtime raises an SIGILL, but we 
 
635
         * checked this with configure */
 
636
        tv = gethrtime();
 
637
        add_randomness( &tv, sizeof(tv), 1 );
 
638
    }
 
639
  #elif defined (HAVE_GETTIMEOFDAY)
 
640
    {   struct timeval tv;
 
641
        if( gettimeofday( &tv, NULL ) )
 
642
            BUG();
 
643
        add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
 
644
        add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
 
645
    }
 
646
  #elif defined (HAVE_CLOCK_GETTIME)
 
647
    {   struct timespec tv;
 
648
        if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
 
649
            BUG();
 
650
        add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
 
651
        add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
 
652
    }
 
653
  #else /* use times */
 
654
    #ifndef HAVE_DOSISH_SYSTEM
 
655
    {   struct tms buf;
 
656
        times( &buf );
 
657
        add_randomness( &buf, sizeof buf, 1 );
 
658
    }
 
659
    #endif
 
660
  #endif
 
661
  #ifdef HAVE_GETRUSAGE
 
662
    #ifndef RUSAGE_SELF
 
663
      #ifdef __GCC__
 
664
        #warning There is no RUSAGE_SELF on this system
 
665
      #endif
 
666
    #else
 
667
    {   struct rusage buf;
 
668
        /* QNX/Neutrino does return ENOSYS - so we just ignore it and
 
669
         * add whatever is in buf.  In a chroot environment it might not
 
670
         * work at all (i.e. because /proc/ is not accessible), so we better 
 
671
         * ignore all error codes and hope for the best
 
672
         */
 
673
        getrusage( RUSAGE_SELF, &buf );
 
674
        
 
675
        add_randomness( &buf, sizeof buf, 1 );
 
676
        memset( &buf, 0, sizeof buf );
 
677
    }
 
678
    #endif
 
679
  #endif
 
680
    /* time and clock are available on all systems - so
 
681
     * we better do it just in case one of the above functions
 
682
     * didn't work */
 
683
    {   time_t x = time(NULL);
 
684
        add_randomness( &x, sizeof(x), 1 );
 
685
    }
 
686
    {   clock_t x = clock();
 
687
        add_randomness( &x, sizeof(x), 1 );
 
688
    }
 
689
}
 
690
 
 
691
 
 
692
 
 
693
static void
 
694
read_random_source( int requester, size_t length, int level )
 
695
{
 
696
    static int (*fnc)(void (*)(const void*, size_t, int), int,
 
697
                                                    size_t, int) = NULL;
 
698
    if( !fnc ) {
 
699
        if( !is_initialized )
 
700
            initialize();
 
701
        fnc = getfnc_gather_random();
 
702
        if( !fnc ) {
 
703
            faked_rng = 1;
 
704
            fnc = gather_faked;
 
705
        }
 
706
        if( !requester && !length && !level )
 
707
            return; /* init only */
 
708
    }
 
709
    if( (*fnc)( add_randomness, requester, length, level ) < 0 )
 
710
        log_fatal("No way to gather entropy for the RNG\n");
 
711
}
 
712
 
 
713
 
 
714
static int
 
715
gather_faked( void (*add)(const void*, size_t, int), int requester,
 
716
              size_t length, int level )
 
717
{
 
718
    static int initialized=0;
 
719
    size_t n;
 
720
    char *buffer, *p;
 
721
 
 
722
    if( !initialized ) {
 
723
        log_info(_("WARNING: using insecure random number generator!!\n"));
 
724
        tty_printf(_("The random number generator is only a kludge to let\n"
 
725
                   "it run - it is in no way a strong RNG!\n\n"
 
726
                   "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
 
727
        initialized=1;
 
728
      #ifdef HAVE_RAND
 
729
        srand(make_timestamp()*getpid());
 
730
      #else
 
731
        srandom(make_timestamp()*getpid());
 
732
      #endif
 
733
    }
 
734
 
 
735
    p = buffer = m_alloc( length );
 
736
    n = length;
 
737
  #ifdef HAVE_RAND
 
738
    while( n-- )
 
739
        *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
 
740
  #else
 
741
    while( n-- )
 
742
        *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
 
743
  #endif
 
744
    add_randomness( buffer, length, requester );
 
745
    m_free(buffer);
 
746
    return 0; /* okay */
 
747
}
 
748
 
 
749