jmst: jmst: The RNG returned by thread_rng() should be guaranteed to be cryptographically secure, since that’s the safe default. An unsafe_thread_rng() could also be provided that is faster but cryptographically insecure. This mimics the Rust policy on hash table where the default is secure (note that misusing an insecure RNG is catastrophic, while misusing an insecure hash table merely leads to denial of service).

I wholeheartedly agree - cryptographically secure by default is a must.

jmst: jmst: Speaking of the reseeding threshold, it is unnecessary if the RNG algorithm is assumed to be cryptographically strong and the seed kept secret, and if that algorithm is broken or if something can inspect the seed, it’s not clear if reseeding would do any good as the attack could often just be repeated, and 32KB of predictable random data is often going to be enough to catastrophically compromise the system. Could still keep it for extra safety, but should perhaps at least set the threshold based on benchmarking to a value that causes minimal overhead (which might already be the case, not sure).

dhardy: dhardy: For the latter, I suspect many of you know more than me, but as I understand it, there are essentially two uses: (1) get a very high quality random number, likely using OS support, and (2) get a pretty good random number more quickly using a cryptographically-proven RNG.

These two speak to a common misconception that I think it’s important we don’t fall prey to: There is precisely one type of cryptographically secure algorithm. There’s no such thing as a CSPRNG that is “pretty good” or that needs to be reseeded in order to be secure. If it has either of those two properties, then it is not cryptographically secure in the first place.

Here are two fantastic resources on the subject:

Myths about /dev/urandom

Recommendations for Randomness in the Operating System - Section 3 of this paper, “Realities of Randomness,” covers a number of common misconceptions (including this one) about cryptographically-secure random number generation.

Why user-space CSPRNGs are dangerous

In section 3.4 of the second paper linked above, entitled “User-Space is a Danger Zone,” the authors lay out a number of points about maintaining CSPRNGs in user space that we should be very careful about. In particular:

Without very careful implementations, user-space CSPRNGs are fork-unsafe. If a process forks, both the parent and child end up with identical copies of memory, which means that unless extra precautions are taken, the two processes’ CSPRNGs will produce identical output after the fork.

There are a number of subtle, surprising ways that the state of a user-space CSPRNG can be leaked - for example, swap space for memory. (see Shredding Your Garbage: Reducing Data Lifetime Through Secure Deallocation)

Reseeding may be required on systems where blocking for sufficient entropy isn’t supported (notably, /dev/random and /dev/urandom on Linux; the getrandom syscall is the recommended mechanism for getting randomness that doesn’t have this limitation, but it is not available on older kernels). In this case, calls made for randomness shortly after boot are insecure for all programs, but for programs that always call out to the kernel for randomness, this problem subsides as soon as the kernel’s entropy pool is properly initialized. On the other hand, a user-space CSPRNG that was seeded before the entropy pool was initialized will continue to be insecure unless it employs reseeding.1

I think that all of these concerns need to be addressed - and more research needs to be done to make sure that there are not more concerns that we should have - before we consider maintaining our own CSPRNGs.

1 It may sound like I’ve just contradicted myself here - didn’t I just say that no CSPRNG should require reseeding? The problem is that kernels which do not support blocking until their entropy pools are initialized (see the second linked paper for details on exactly what this means) provide insecure randomness. Thus, while a CSPRNG that is seeded with a cryptographically-secure seed should never need to be reseeded, a CSPRNG whose seed is acquired before the entropy pool is initialized is an exception because its seed is not cryptographically secure. In other words, the CSPRNG didn’t screw up, the kernel screwed up, and now we’re left to try to patch things over.