~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to cipher/random.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

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