If you are on Linux,
just use /dev/urandom — and
don't worry, what you've heard about it being cryptographically insecure
is a myth.
Update:
I wrote the following code at a time when I still thought /dev/urandom
was inferior to /dev/random (spoiler: it isn't). At least on Linux,
there's no need to treat /dev/random as a scarce source of “real” or
secure random bytes and use it to initialise your own cryptographically
secure PRNG. Maybe it's still needed on other systems. I don't know.
I don't think there's anything wrong with the code below, so
I've retained it because it shows a useful way to initialise the
Data::Entropy module. Just remember that my original premise for doing
things this way was based on a… 😎 myth-understanding of /dev/urandom.
On Linux, /dev/random is a good, cryptographically secure pseudorandom
number generator, but the entropy available without special hardware
support is limited. Entropy is in demand throughout the system, so reads
from /dev/random will block for however long it takes to gather enough
entropy to satisfy the request.
One standard solution to this problem is to use the output of a randomly
keyed block cipher running in counter (CTR) mode. This provides only as
much entropy as the random key, but if /dev/random is used to generate
the key, the result is suitable for many purposes. Andrew Main's
Data::Entropy
module implements this strategy in Perl.
Setting up Data::Entropy is a bit complicated. One must create a
RawSource::Local to read from /dev/random, wrap that in a Source, read a
256-bit key from it and use that to set up Crypt::Rijndael, feed that to
a RawSource::CryptCounter, and wrap the result in another Source, set it
as the default entropy_source using with_entropy_source, and finally use
D::E::Algorithms to fetch random numbers in whatever format is desired.
Here's how I did all that.
use Crypt::Rijndael;
use Data::Entropy qw(with_entropy_source entropy_source);
use Data::Entropy::Algorithms qw(rand_bits rand_int ...);
use Data::Entropy::RawSource::CryptCounter;
use Data::Entropy::RawSource::Local;
use Data::Entropy::Source;
with_entropy_source(
Data::Entropy::Source->new(
Data::Entropy::RawSource::Local->new("/dev/random"),
"sysread"),
sub {
$main::prng = Data::Entropy::Source->new(
Data::Entropy::RawSource::CryptCounter->new(
Crypt::Rijndael->new(entropy_source->get_bits(256))),
"sysread");
}
);
with_entropy_source $main::prng, sub {
$bits = rand_bits(256);
...
};