1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
#pike __REAL_VERSION__
#pragma strict_types
#require constant(Nettle.Fortuna)
//! This module contains a pseudo random number generator (PRNG)
//! designed to give you the best possible random number generation.
//! The current design is based on the Fortuna PRNG, but uses the
//! system random source as input.
protected class RND
{
inherit Nettle.Fortuna;
protected function(int:string(8bit)) source;
protected void create()
{
#if constant(Nettle.NT)
source = Nettle.NT.CryptContext(0, 0, Nettle.NT.PROV_RSA_FULL,
Nettle.NT.CRYPT_VERIFYCONTEXT )->read;
#else
source = Stdio.File("/dev/urandom")->read;
#endif
// random_string() is either seeded with time and PID in the
// master, or outputs data from RDRND. Both of these are
// (partially) independent from /dev/urandom, which gives some
// protection against a /dev/urandom exploit.
reseed(source(32)+predef::random_string(32));
}
System.Timer last_seed = System.Timer();
void reseed(string(8bit)data)
{
last_seed->get();
::reseed(data);
}
string(8bit) random_string(int len)
{
// The original Fortuna design has an entropy pool reseeding the
// generator when enough external events have been collected, but
// not more often than every 100 ms. Since we are pulling entropy
// rather than having it pushed, we do it if more than 100 ms has
// passed since last call.
//
// An alternative here would be to asynchronously pull data every
// 100 ms to hide entropy consumption from an external obserer,
// but that requires a backend, and is likely a waste of effort.
if( last_seed->peek()>0.1 )
reseed(source(32));
return ::random_string(len);
}
}
protected RND rnd_obj = RND();
protected function(int:string(8bit)) rnd_func = rnd_obj->random_string;
//! Returns a string of length @[len] with random content. The content
//! is generated by a Fortuna random generator that is updated with
//! output from /dev/urandom on UNIX and CryptGenRandom on NT.
string(8bit) random_string(int len) {
return rnd_func(len);
}
__deprecated__ string(8bit) blocking_random_string(int len)
{
return rnd_func(len);
}
//! Returns a @[Gmp.mpz] object with a random value between @expr{0@}
//! and @[top]. Uses @[random_string].
Gmp.mpz random(int top) {
return [object(Gmp.mpz)]( Gmp.mpz(rnd_func( (int)ceil( log((float)top)/
log(2.0) ) ),
256) % top);
}
//! Inject additional entropy into the random generator. One possible
//! use is to persist random data between executions of an
//! application. The internal state is approximately 256 bits, so
//! storing 32 bytes from @[random_string()] at shutdown and injecting
//! them through @[add_entropy()] agan at startup should carry over
//! the entropy. Note that this doesn't affect the independent
//! initialization that happens in the generator at startup, so the
//! output sequence will be different than if the application had
//! continued uninterrupted.
//! @param data
//! The random string.
void add_entropy(string(8bit) data) {
rnd_obj->reseed(data);
}
|