# Cryptographically secure randomness in Perl

By Abhijit Menon-Sen <ams@toroid.org>

I can usually sidestep the need for cryptographically secure randomness, but I decided to investigate the available options to generate CSRF protection tokens.

On Linux, /dev/random is a good, cryptographically secure random number generator, but the entropy available without special hardware support is severely limited. Reads from /dev/random block for however long it takes (even minutes) to gather enough entropy to satisfy the request. Entropy is in high demand throughout the system, so this is not a resource that can be indiscriminately drawn upon.

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.

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; my $really_secure = 1; with_entropy_source( Data::Entropy::Source->new( Data::Entropy::RawSource::Local->new("/dev/urandom"), "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); ... };

Given that the above code is something of a best practice, Andrew plans to make the module easier to use in this configuration in future.