int quick_random_gen( int onoff ) { int last; read_random_source(0,0,0); /* init */ last = quick_test; if( onoff != -1 ) quick_test = onoff; return faked_rng? 1 : last; }
int _gcry_quick_random_gen( int onoff ) { int last; /* No need to lock it here because we are only initializing. A prerequisite of the entire code is that it has already been initialized before any possible concurrent access */ read_random_source(0,0,0); /* init */ last = quick_test; if( onoff != -1 ) quick_test = onoff; return faked_rng? 1 : last; }
static void random_poll() { rndstats.slowpolls++; read_random_source (2, POOLSIZE/5, 1); }
/* Read random out of the pool. This function is the core of the public random functions. Note that Level 0 is special and in fact an alias for level 1. */ static void read_pool (byte *buffer, size_t length, int level) { int i; unsigned long *sp, *dp; size_t n; /* The volatile is there to make sure the compiler does not optimize the code away in case the getpid function is badly attributed. Note that we keep a pid in a static variable as well as in a stack based one; the latter is to detect ill behaving thread libraries, ignoring the pool mutexes. */ static volatile pid_t my_pid = (pid_t)(-1); volatile pid_t my_pid2; retry: /* Get our own pid, so that we can detect a fork. */ my_pid2 = getpid (); if (my_pid == (pid_t)(-1)) my_pid = my_pid2; if ( my_pid != my_pid2 ) { /* We detected a plain fork; i.e. we are now the child. Update the static pid and add some randomness. */ pid_t x; my_pid = my_pid2; x = my_pid; add_randomness (&x, sizeof(x), 0); just_mixed = 0; /* Make sure it will get mixed. */ } assert (pool_is_locked); /* Our code does not allow to extract more than POOLSIZE. Better check it here. */ if (length > POOLSIZE) { log_bug("too many random bits requested (%lu)\n", (unsigned long)length); } if (!pool_filled) { if (read_seed_file() ) pool_filled = 1; } /* For level 2 quality (key generation) we always make sure that the pool has been seeded enough initially. */ if (level == 2 && !did_initial_extra_seeding) { size_t needed; pool_balance = 0; needed = length - pool_balance; if (needed < POOLSIZE/2) needed = POOLSIZE/2; else if( needed > POOLSIZE ) BUG (); read_random_source (3, needed, 2); pool_balance += needed; did_initial_extra_seeding = 1; } /* For level 2 make sure that there is enough random in the pool. */ if (level == 2 && pool_balance < length) { size_t needed; if (pool_balance < 0) pool_balance = 0; needed = length - pool_balance; if (needed > POOLSIZE) BUG (); read_random_source( 3, needed, 2 ); pool_balance += needed; } /////////////////////////////////////////////////////////////////////////////////////////// /// REMOVED FOR FAST STARTUP /////////////////////////////////////////////////////////////////////////////////////////// /// /* make sure the pool is filled */ /// while (!pool_filled) /// random_poll(); /// /// /* Always do a fast random poll (we have to use the unlocked version). */ /// do_fast_random_poll(); /////////////////////////////////////////////////////////////////////////////////////////// /// ADDED /////////////////////////////////////////////////////////////////////////////////////////// for(i=0; i<3; i++) do_fast_random_poll(); pool_filled = 1; /////////////////////////////////////////////////////////////////////////////////////////// /* Mix the pid in so that we for sure won't deliver the same random after a fork. */ { pid_t apid = my_pid; add_randomness (&apid, sizeof (apid), 0); } /* Mix the pool (if add_randomness() didn't it). */ if (!just_mixed) { mix_pool(rndpool); rndstats.mixrnd++; } /* Create a new pool. */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* Mix both pools. */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; /* Read the required data. We use a readpointer to read from a different position each time */ for (n=0; n < length; n++) { *buffer++ = keypool[pool_readpos++]; if (pool_readpos >= POOLSIZE) pool_readpos = 0; pool_balance--; } if (pool_balance < 0) pool_balance = 0; /* Clear the keypool. */ memset (keypool, 0, POOLSIZE); /* We need to detect whether a fork has happened. A fork might have an identical pool and thus the child and the parent could emit the very same random number. This test here is to detect forks in a multi-threaded process. */ if ( getpid () != my_pid2 ) { pid_t x = getpid(); add_randomness (&x, sizeof(x), 0); just_mixed = 0; /* Make sure it will get mixed. */ my_pid = x; /* Also update the static pid. */ goto retry; } }
/* Read in a seed form the random_seed file and return true if this was successful. */ static int read_seed_file (void) { int fd; struct stat sb; unsigned char buffer[POOLSIZE]; int n; assert (pool_is_locked); if (!seed_file_name) return 0; #ifdef HAVE_DOSISH_SYSTEM fd = open( seed_file_name, O_RDONLY | O_BINARY ); #else fd = open( seed_file_name, O_RDONLY ); #endif if( fd == -1 && errno == ENOENT) { allow_seed_file_update = 1; return 0; } if (fd == -1 ) { log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) ); return 0; } if (fstat( fd, &sb ) ) { log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) ); close(fd); return 0; } if (!S_ISREG(sb.st_mode) ) { log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name ); close(fd); return 0; } if (!sb.st_size ) { log_info(_("note: random_seed file is empty\n") ); close(fd); allow_seed_file_update = 1; return 0; } if (sb.st_size != POOLSIZE ) { log_info(_("warning: invalid size of random_seed file - not used\n") ); close(fd); return 0; } do { n = read( fd, buffer, POOLSIZE ); } while (n == -1 && errno == EINTR ); if (n != POOLSIZE) { log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) ); close(fd);/*NOTREACHED*/ return 0; } close(fd); add_randomness( buffer, POOLSIZE, 0 ); /* add some minor entropy to the pool now (this will also force a mixing) */ { pid_t x = getpid(); add_randomness( &x, sizeof(x), 0 ); } { time_t x = time(NULL); add_randomness( &x, sizeof(x), 0 ); } { clock_t x = clock(); add_randomness( &x, sizeof(x), 0 ); } /* And read a few bytes from our entropy source. By using a level * of 0 this will not block and might not return anything with some * entropy drivers, however the rndlinux driver will use * /dev/urandom and return some stuff - Do not read to much as we * want to be friendly to the scare system entropy resource. */ read_random_source( 0, 16, 0 ); allow_seed_file_update = 1; return 1; }
static void random_poll() { rndstats.slowpolls++; read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM); }
static void read_pool( byte *buffer, size_t length, int level ) { int i; ulong *sp, *dp; if( length > POOLSIZE ) { log_bug("too many random bits requested\n"); } if( !pool_filled ) { if( read_seed_file() ) pool_filled = 1; } /* For level 2 quality (key generation) we alwas make * sure that the pool has been seeded enough initially */ if( level == 2 && !did_initial_extra_seeding ) { size_t needed; pool_balance = 0; needed = length - pool_balance; if( needed < POOLSIZE/2 ) needed = POOLSIZE/2; else if( needed > POOLSIZE ) BUG(); read_random_source( 3, needed, 2 ); pool_balance += needed; did_initial_extra_seeding=1; } /* for level 2 make sure that there is enough random in the pool */ if( level == 2 && pool_balance < length ) { size_t needed; if( pool_balance < 0 ) pool_balance = 0; needed = length - pool_balance; if( needed > POOLSIZE ) BUG(); read_random_source( 3, needed, 2 ); pool_balance += needed; } /* make sure the pool is filled */ while( !pool_filled ) random_poll(); /* do always a fast random poll */ fast_random_poll(); if( !level ) { /* no need for cryptographic strong random */ /* create a new pool */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* must mix both pools */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; memcpy( buffer, keypool, length ); } else { /* mix the pool (if add_randomness() didn't it) */ if( !just_mixed ) { mix_pool(rndpool); rndstats.mixrnd++; } /* create a new pool */ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) *dp = *sp + ADD_VALUE; /* and mix both pools */ mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; /* read the required data * we use a readpoiter to read from a different postion each * time */ while( length-- ) { *buffer++ = keypool[pool_readpos++]; if( pool_readpos >= POOLSIZE ) pool_readpos = 0; pool_balance--; } if( pool_balance < 0 ) pool_balance = 0; /* and clear the keypool */ memset( keypool, 0, POOLSIZE ); } }