The core of the Random Number Generator and the source of the seeds required
for the generation of pseudorandom bits is a 384-byte randomness pool
that is periodically replenished with random data collected from various
physical sources using an algorithm designed to meet the following requirements:
-
An adversary with full knowledge of the underlying software, hardware,
and all sources of randomness must not be able to predict the pool
content.
-
At any given instance, if the internal state of the generator becomes
available to the adversary, the safety of the past outputs must remain
intact.
To ensure that these requirements are met, the pool is refilled with new random data from a variety
of highly unpredictable sources so that should any of them fail, the security of the generator is not
compromised. The following are the sources used to fill the randomness pool:
-
Fast entropy sources collected at 500 ms intervals:
- Thread and process information and memory status.
- High-precision CPU timestamps and system counters.
- Various Win32 handles and window information.
- MS Windows BCryptGenRandom.
- x86 on-chip hardware RNG (RDSEED and RDRAND).
-
Slow entropy sources:
- Hardware RNG based on CPU timing jitter.
- Disk I/O statistics.
- System performance and interrupt information.
- Networking statistics for TCP/IP and Lanman.
- CoreTemp CPU temeratures.
- GPU-Z hardware information.
- Mouse movement and user keystrokes.
Instead of overwriting the existing data in the pool, the new data obtained from the above sources is
added to the pool using modulo 2
8 addition, which ensures an increase in the pool's entropy over
time.
Mixing The Pool
The pool mixing operation is at done frequent intervals, for example after every
32 bytes written to the pool and each time before any output is generated from it.
This step performs diffusion within the pool while preserving its total entropy
which ensures that every bit in the pool affects every other bit and also removes
statistical biases.
This RNG uses a cryptographically secure one-way hash function to transform the content of the pool using the
following procedure:
Let p be the size of the randomness pool.
Let SHA512 be the underlying hash function with the digest size d.
Let P
i be the i-th block of size d, where the number of blocks in the pool is given by n = p/d.
Let R
i be the i-th block of the new pool after the mixing operation has been applied to it.
for i = 0 to n-1 do
H = SHA512(R0 || R1 || ... || Ri-1 || Pi || Pi+1 ||
... || Pn-1)
Ri = Pi ^ H
done
For example,
R0 = P0 ^ SHA512(P0 || P1 || P2 || ... ||
Pn-1)
R1 = P1 ^ SHA512(R0 || P1 || P2 || ... ||
Pn-1)
R2 = P2 ^ SHA512(R0 || R1 || P2 || ... ||
Pn-1)
.
.
.
Rn-1 = Pn-1 ^ SHA512(R0 || R1 || R2 || ... ||
Rn-2 || Pn-1)
Hence, we obtain the new pool R = R
0 || R
1 || ... || R
n-1
Generating Random Values
While extracting data from the pool, its content is never directly copied to the destination. Therefore,
even if an attacker obtains the output generated by the RNG, it is infeasible for him to determine any prior
outputs. The following procedure is followed to extract data from the pool:
-
If there hasn't been a slow poll at least once, call the slow poll function to collect new random data
from
the system and add it to the pool.
-
After every byte is written to the output buffer, the pool read cursor advances by
one
byte. If the cursor reaches the end of the pool, it wraps back to the beginning.
-
Mix the pool and XOR its content to the output buffer.
Invert every bit in the pool and mix it again to create the new pool and XOR its content to the output
buffer.
-
Mix the pool one final time (this does not affect the final output) and export the final value to the
caller.
The pool mixing operation is done thrice in the above process: the first time to create a dependency of the
generated output on the entire pool content and to prevent state leaks in case the attacker has access to
values in the memory, a second time after inverting the bits to create the new pool, and a final third time so
that the generated output is not compromised even if the adversary has an opportunity to read the pool content
at a later stage.
Fast DRBG For Pseudorandom Data
Although maximum bit strength is necessary for purposes like key generation, the aforementioned method of
extracting entropy from a running system is very slow in practice. For weaker uses like nonces,
initialization vectors, and salts, a compromise can be made in the strength reserve of the required data to
achieve a higher bit rate. Xrand has a Deterministic Random Bit Generator (DRBG) to serve such purposes,
which is based on the CTR_DRBG mechanism specified by
SP 800-90A. This implementation uses AES-256 in counter mode as the underlying block cipher without
a
derivation function or prediction resistance.
The DRBG is periodically seeded with full entropy data from the main RNG and the pseudorandom bits are generated
by repeatedly updating the internal state of the DRBG using the AES operation with the random data as the key
and
a sequentially updated 128-bit counter.
References And Design Origins
The Random Number Generator is based on the following publications and existing designs:
- Cryptographic Random Numbers by Carl Ellison.
- Software Generation of Practically Strong Random Numbers by Peter Gutmann.
- Random Number Generators - Principles and Practices by David Johnston.
- The TrueCrypt Random Number Generator.
- The GnuPG Random-Number Subsystem
Architecture.
Written by Vibhav Tiwari for Xrand