-
Notifications
You must be signed in to change notification settings - Fork 22
Random Number Generators
The random number generators provided in Botan are meant for creating
keys, IVs, padding, nonces, and anything else that requires 'random'
data. It is important to remember that the output of these classes
will vary, even if they are supplied with the same seed (ie, two
Randpool
objects with similar initial states will not produce the
same output, because the value of high resolution timers is added to
the state at various points).
To create a random number generator, instantiate a AutoSeededRNG
object. This object will handle choosing the right algorithms from the
set of enabled ones and doing seeding using OS specific
routines. The main service a RandomNumberGenerator provides is, of
course, random numbers:
ubyte random();
Generates a single random byte and returns it
void randomize(ubyte* data, size_t length);
Places length
bytes into the array pointed to by data
To ensure good quality output, a PRNG needs to be seeded with truly random data. Normally this is done for you. However it may happen that your application has access to data that is potentially unpredictable to an attacker. If so, use
void addEntropy(in ubyte* data, size_t length);
which incorporates the data into the current randomness state. Don't worry about filtering the data or doing any kind of cryptographic preprocessing (such as hashing); the RNG objects in botan are designed such that you can feed them any arbitrary non-random or even maliciously chosen data - as long as at some point some of the seed data was good the output will be secure.
Randpool
is the primary PRNG within Botan. In recent versions all
uses of it have been wrapped by an implementation of the X9.31 PRNG
(see below). If for some reason you should have cause to create a PRNG
instead of using the "global" one owned by the library, it would be
wise to consider the same on the grounds of general caution; while
Randpool
is designed with known attacks and PRNG weaknesses in
mind, it is not an standard/official PRNG. The remainder of this
section is a (fairly technical, though high-level) description of the
algorithms used in this PRNG. Unless you have a specific interest in
this subject, the rest of this section might prove somewhat
uninteresting.
Randpool
has an internal state called pool, which is 512 bytes
long. This is where entropy is mixed into and extracted from. There is also a
small output buffer (called buffer), which holds the data which has already
been generated but has just not been output yet.
It is based around a MAC and a block cipher (which are currently HMAC(SHA-256) and AES-256). Where a specific size is mentioned, it should be taken as a multiple of the cipher's block size. For example, if a 256-bit block cipher were used instead of AES, all the sizes internally would double. Every time some new output is needed, we compute the MAC of a counter and a high resolution timer. The resulting MAC is XORed into the output buffer (wrapping as needed), and the output buffer is then encrypted with AES, producing 16 bytes of output.
After 8 blocks (or 128 bytes) have been produced, we mix the pool. To do this, we first rekey both the MAC and the cipher; the new MAC key is the MAC of the current pool under the old MAC key, while the new cipher key is the MAC of the current pool under the just-chosen MAC key. We then encrypt the entire pool in CBC mode, using the current (unused) output buffer as the IV. We then generate a new output buffer, using the mechanism described in the previous paragraph.
To add randomness to the PRNG, we compute the MAC of the input and XOR
the output into the start of the pool. Then we remix the pool and
produce a new output buffer. The initial MAC operation should make it
very hard for chosen inputs to harm the security of Randpool
, and
as HMAC should be able to hold roughly 256 bits of state, it is
unlikely that we are wasting much input entropy (or, if we are, it
doesn't matter, because we have a very abundant supply).
ANSIX931PRNG
is the standard issue X9.31 Appendix A.2.4 PRNG,
though using AES-256 instead of 3DES as the block cipher. This PRNG
implementation has been checked against official X9.31 test vectors.
Internally, the PRNG holds a pointer to another PRNG (typically Randpool). This internal PRNG generates the key and seed used by the X9.31 algorithm, as well as the date/time vectors. Each time an X9.31 PRNG object receives entropy, it passes it along to the PRNG it is holding, and then pulls out some random bits to generate a new key and seed. This PRNG considers itself seeded as soon as the internal PRNG is seeded.
An EntropySource
is an abstract representation of some method of
gather "real" entropy. This tends to be very system dependent. The
only way you should use an EntropySource
is to pass it to a PRNG
that will extract entropy from it -- never use the output directly for
any kind of key or nonce generation!
Note for writers of EntropySource
subclasses: it isn't necessary
to use any kind of cryptographic hash on your output. The data
produced by an EntropySource is only used by an application after it
has been hashed by the RandomNumberGenerator
that asked for the
entropy, thus any hashing you do will be wasteful of both CPU cycles
and entropy.