I wholeheartedly agree - cryptographically secure by default is a must.
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:
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/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.
To be clear, this is only a problem on systems that do not support blocking calls for entropy until the entropy pool is initialized. The primary culprit here is old versions of Linux - new versions support the
getrandom syscall, which does block properly.