Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use boost::random_device to generate a cryptographically secure 64 bit integer?

I would like to do something like this:

boost::random_device rd;
boost::random::mt19937_64 gen(rd());
boost::random::uniform_int_distribution<unsigned long long> dis;
uint64_t value = dis(gen);

But I've read that a mersenne twister is not cryptographically secure. However, I've also read that a random_device could be, if its pulling data from /dev/urandom which is likely on a linux platform (my main platform). So if the random_device is non-deterministically random and its used to seed the mersenne twister (as shown above), doesn't that also make the mersenne twister cryptographically secure (even though by itself, it isn't)?

I'm a bit of a novice in this arena so any advice is appreciated.

So, how can I generate a cryptographically secure 64 bit number that can be stored in a uint64_t?

Thanks,

Ben.

like image 705
Ben J Avatar asked Apr 29 '14 18:04

Ben J


1 Answers

Analyzing your question is harder than it might seem:

You seed the mersenne twister with rd(), which returns an unsigned int, and therefore (on most platforms) contains at most 32 random bits.

Everything that the mersenne twister does from this point on is determined by those 32 bits.

This means that the value can only take on 2**32 different values, which can be a problem if any attack vector exists that attacks whatever you do with this number by brute force. In fact, the mersenne twister's seeding routine may even reduce the number of possible values for the first result, since it distributes the 32 random bits over its complete state (to ensure that this is not the case you would have to analyse the seed routine boost uses).

The primary weakness of the mersenne twister (its state can be derived after seeing 624 numbers) is not even of interest in this case however, since you generate a sequence that is so short (1 value).

Generating 64 cryptographically secure bits

Assuming that unsigned int is equivalent to uint32_t on your platform, you can easily generate 64 cryptographically secure random bits by using boost::random_device:

boost::random_device rd;
std::uint64_t value = rd();
value = (value << 32) | rd();

This is fairly secure, since the implementations for both linux and windows use the operating system's own cryptographically secure randomness sources.

Generating cryptographically secure values with arbitrary distributions

While the previous works well enough, you may wish for a more flexible solution. This is easy to do by realizing that you can actually use the random distributions boost provides with random_device as well. A simple example would be to rewrite the previous solution like this:

boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
std::uint64_t value = dis(rd);

(While this can in theory also provide a more robust solution if the previous one does not actually contain a number in [0, 2**32), this is not a problem in practice.)

Binding distribution to generator

To improve usability you will often find usage of boost::bind to bind distribution and generator together. Since boost::bind copies its arguments, and the copy ctor is deleted for boost::random_device, you need to use a little trick:

boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
boost::function<std::uint64_t()> gen = boost::bind(dis, boost::ref(rd));
std::uint64_t value = gen();
like image 200
gha.st Avatar answered Nov 13 '22 11:11

gha.st