Cryptographically secure randomness in Perl

By Abhijit Menon-Sen <>

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);
    ...
};