The gist of this post is that if your program or library has its own PRNG, I
would like you to remove it. If you are not convinced that this is a good
idea, read on; if you want links on what to do instead, skip to the second
Why do you have this?
I believe in code re-use, in not re-inventing the wheel where necessary, and
in cooperation. So if code to do something exists, and there are no strong
reasons why I shouldn’t use it: I use it. Formulated in this manner it sounds
almost like a strict rule; in practice, the same result can be achieved for
new code just by laziness. For existing code, it becomes a maintainability
question. I maintain code as well as writing it (as everyone who writes code
should), and while I won’t deny a certain satisfaction in well-oiled
machinery, less would be better. So everything we maintain should serve a
purpose, and reducing unneeded size, scope, and complexity are worthwhile.
Every project is different, which means your project’s reasons for having a
PRNG will be different as well. Maybe it doesn’t care about the quality of
the pseudorandom numbers (at which point it should probably just read
/dev/urandom). Or maybe it’s performing cryptographic operations (use
getrandom(2) or similar). But I invite you to think about whether
continuing to maintain your own is worth it, or whether it might be better to
use something which has been more strongly audited (e.g., the kernel CSPRNG).
To look at an example: a few months ago now, I performed this change for krb5.
In our case, we had a Fortuna implementation because quality entropy used to
be difficult to come by. Fortuna specifically was used due to its ability to
recover from low-quality input. However, upon further examination, the time
to recover is quite long (so it only really helps the server), and in the mean
time, operation will appear to be normal, with low quality random numbers.
Since there’re already quality random numbers available on all server
platforms we support, I added the option to just use them directly. (This
describes the current behavior on Fedora, as well as the behavior for all
future RHEL/CentOS releases).
What to do instead
Anyway, the short answer is: you should use
The longer answer is just me telling you how to use
getrandom(2). For that,
I want to draw from this post which
contains a useful diagram about how /dev/random and /dev/urandom relate. The
author points out two issues with using /dev/urandom directly on Linux (that
do not occur on certain BSD, where one just uses /dev/random instead):
First, that /dev/urandom is not guaranteed to be seeded.
actually provides seeding guarantees by default. More precisely, it will
block the call until the requested number of bytes can be generated; in the
case of the urandom pool, this means until the pool has been seeded. (If
this behavior is not desired, one should just read directly from
Second, that one may wish to use /dev/random despite it being slower if
they’re feeling especially paranoid. There’s a
this, it turns out:
There’s one pitfall with this approach, which is that (for reasons that are
opaque to me) glibc was slow to add a wrapper for this function. (See:
upstream.) So if you
want to support older versions of glibc, you have to use
A while back, I remember reading (but can no longer find) a post which
surveyed open source software’s usage of
rand()/srand() and related
functions. There were some decidedly bizarre usages in there, but most of
them were just run-of-the-mill incorrect. Anyway, inspired by that, I’ve been
toying with the idea of writing a shim library of sorts to make these
functions actually return cryptographically random numbers, discarding seeding
and such. The only real pitfall I’m aware of with this is users of these
functions that expect deterministic behavior, but I’m not really sure I want
to care. Maybe an environment variable for configuration or something.