Linux Random Number Generator

The venerable Linux /dev/random served users of cryptographic mechanisms well for a long time. Its behavior is well understood to deliver entropic data. In the last years, however, the Linux /dev/random showed signs of age where it has challenges to cope with modern computing environments ranging from tiny embedded systems, over new hardware resources such as SSDs, up to massive parallel systems as well as virtualized environments. This paper proposes a new approach to entropy collection in the Linux kernel with the intention of addressing all identified shortcomings of the legacy /dev/random implementation. The new Linux Random Number Generator's design is presented and all its cryptographic aspects are backed with qualitative assessment and complete quantitative testing. The test approaches are explained and the test code is made available to allow researchers to re-perform these tests.

To clarify the question whether sufficient entropy is present during boot
I added one more test in 3.3.1 which demonstrates the providing of
sufficient entropy during initialization. In the worst case of no fast noise
sources, in the worst case of a virtual machine with only very few hardware
devices, the testing shows that the secondary DRBG is fully seeded with 256
bits of entropy before user space injects the random data obtained
during shutdown of the previous boot (i.e. the requirement phrased by the
legacy /dev/random implementation). As the writing of the random data into
/dev/random by user space will happen before any cryptographic service
is initialized in user space, this test demonstrates that sufficient
entropy is already present in the LRNG at the time user space requires it
for seeding cryptographic daemons. Note, this test result was obtained
for different architectures, such as x86 64 bit, x86 32 bit, ARM 32 bit and
MIPS 32 bit.

Add handling logic for systems without high-res timer as suggested by Pavel
Machek -- it uses ideas from the add_interrupt_randomness of the legacy
/dev/random implementation

add per NUMA node secondary DRBGs as suggested by Andi Kleen -- the
explanation of how the logic works is given in section 2.1.1 of my
documentation [1], especially how the initial seeding is performed.

Use classical twisted LFSR approach to collect entropic data as requested by
George Spelvin. The LFSR is based on a primitive and irreducible polynomial
whose taps are not too close to the location the current byte is mixed in.
Primitive polynomials for other entropy pool sizes are offered in the code.

The reading of the entropy pool is performed with a hash. The hash can be specified at compile time. The pre-defined hashes are the same as used for the DRBG type (e.g. a SHA256 Hash DRBG implies the use of SHA-256, an AES256 CTR DRBG implies the use of CMAC-AES).

Addition of the example defines for a CTR DRBG with AES128 which can be
enabled during compile time.

Entropy estimate: one bit of entropy per interrupt. In case a system does
not have a high-resolution timer, apply 1/10th bit of entropy per interrupt.
The interrupt estimates can be changed arbitrarily at compile time.

Use kmalloc_node for the per-NUMA node secondary DRBGs.

Add boot time entropy tests discussed in section 3.4.3 [1].

Align all buffers that are processed by the kernel crypto API to an 8 byte
boundary. This boundary covers all currently existing cipher implementations.

use CTR DRBG with AES256 as default due to its superior speed -- on X86_64
executing within a KVM I get read speeds of up to 850 MB/s now. When using a
fake NUMA system with 4 nodes on 4 CPUs, I still get up to 430 MB/s read speed
with four parallel reads. Note, this patch applies to the current cryptodev-2.6 tree.

simplify lrng_get_arch

use DRBG security strengths as defined in SP800-57 section 5.6.1

add security strength to /proc/sys/kernel/random/lrng_type

add ChaCha20 DRNG: in case the kernel crypto API is not compiled, the ChaCha20
DRNG with the SHA-1 C implementations are used to drive the cryptographic part
of the LRNG.The ChaCha20 RNG is described in [1]. I analyzed it with a user
space version of it.

set read wakeup threshold to 64 bits to comply with legacy /dev/random

simplify the interrupt to entropy amount conversion code

move wakeup call of entropy-providers to a code location where /dev/urandom
will benefit from the wake up as well (i.e. when the primary DRBG entropy
runs low because of /dev/urandom reseeds, the entropy provider is woken up)

inject current time into primary DRBG at the time of seeding from noise
sources (suggested by Sandy Harris)

SHA-256 based DRBG have a security strength of 256 bits as per SP800-57A table 3

Increase LRNG_MIN_SEED_ENTROPY_BITS to 128 bits based on updates proposed to FIPS 140-2 and BSI's TR02102

when writing/IOCTL to /dev/random or /dev/urandom, the data is only inserted into the primary DRBG, the secondary DRBG(s) will forcefully reseeded when processing next request for the respective secondary DRBG instead of injecting the input data also into the secondary DRBGs

Use RDSEED for seeding operations and RDRAND as a fallback as suggested by DJ Johnston (note, the final fallback to use a high-resolution timer is implicitly present by using the time stamp unconditional for each reseed).