librandombytes

The standard security goal for a random-number generator (RNG) is that no feasible computation can distinguish the RNG output from true randomness, i.e., from a uniform random string of the same length. This allows applications to treat the RNG output as true randomness.

Beyond merely asking for indistinguishability, some applications ask for "forward secrecy". This means that the RNG output is indistinguishable from true randomness for an attacker who sees the subsequent state of the entire device, including the internal state of the RNG.

A typical explanation of the importance of forward secrecy is as follows: "A rogue country's spy agency has intercepted ciphertexts that a whistleblower has sent to a journalist. Agents then grab the whistleblower's computer while the computer is unlocked, take it away for analysis, and see that the whistleblower deleted the messages after sending them. Can the agency use the computer's current RNG state to reconstruct old keys and decrypt the ciphertexts?"

Sometimes there are also requests for "backward secrecy". A strict interpretation of backward secrecy says that an attacker who sees the state of the entire device cannot distinguish the next RNG output from uniform. A weaker variant is for secrecy to eventually be restored after a compromise. Either way, backward secrecy is advertised as providing "self-healing", "post-compromise security", etc. Beware that this assumes a questionable concept of compromise as a one-time event rather than a naturally persistent state; meanwhile the complications of trying to achieve "post-compromise security" have a long history of distracting attention from the more fundamental task of preventing compromises in the first place.

Whether or not backward secrecy is desired, there are many ways for RNGs to fail to provide forward secrecy, or to fail to even reach the standard security goal. For example:

Furthermore, RNG security can be compromised by implementation failures. For example:

RNG failures are often used as motivation for the development of further RNGs, but if this process is not carefully managed then it increases the load on reviewers and encourages further security problems.

librandombytes does not provide a new RNG; it is a wrapper around existing RNGs. It does not wrap every available RNG; it limits the number of options to simplify review. It takes the maximally centralized option, the OS kernel's RNG, by default; it provides one backup option, the OpenSSL RNG, just in case this is critical for system performance.

Usage of the OS kernel's RNG has an imperfect track record, as illustrated by the papers from 2012 cited above. This is concerning. However, there are reasons to believe that risks have been reduced:

librandombytes-kernel uses getrandom if it finds it, otherwise getentropy if it finds it, otherwise /dev/urandom. In the case of /dev/urandom, librandombytes-kernel waits at program startup for /dev/random to become readable; however, it skips this if the file /var/run/urandom-ready exists (or if /dev/random does not exist).

The idea is that system administrators of Linux systems too old to have getrandom can run

dd count=1 bs=64 if=/dev/random of=/dev/urandom status=none \
&& findmnt -t tmpfs -T /var/run >/dev/null \
&& touch /var/run/urandom-ready &

from boot scripts so that librandombytes-kernel doesn't wait after initial per-boot entropy collection. Note that systems where /var/run is a persistent directory (rather than tmpfs), cleared by boot scripts, should not create /var/run/urandom-ready, since librandombytes-kernel might be running earlier in the boot process.

There are various other ways that one can imagine /dev/urandom being read too early on old Linux systems (and not so old, as in the 2018 Linux bug mentioned above); librandombytes-kernel tries to reduce risks but does not make guarantees. Provisioning systems with initial randomness is recommended in all cases. There are also many other security reasons to recommend retiring old Linux systems if they cannot be upgraded.

librandombytes-openssl, which simply calls OpenSSL's RAND_bytes, raises more security concerns:

These OpenSSL issues are not obviously showstoppers. For systems where using the OS RNG is a performance problem, OpenSSL's RNG seems to be a reasonable backup plan. Of course, it would be possible to patch OpenSSL to use a fast-key-erasure RNG on top of ChaCha20, to use a safer /dev/random test (which could also be handled as a wrapper around OpenSSL), and to reseed more frequently.


Version: This is version 2023.09.04 of the "Security" web page.