I want to generate cryptographically strong pseudorandom numbers in erlang for session IDs.
There is crypto:strong_rand_bytes(N). What if it throws the low_entropy exception?
From http://www.erlang.org/doc/man/crypto.html#strong_rand_bytes-1
strong_rand_bytes(N) -> binary()
Types: N = integer()
Generates N bytes randomly uniform 0..255, and returns the result in a binary. Uses a cryptographically secure prng seeded and periodically mixed with operating system provided entropy. By default this is the RAND_bytes method from OpenSSL.
May throw exception low_entropy in case the random generator failed due to lack of secure "randomness".
I guess a fallback to just rand_bytes(N) is not a good way.
Handle it by not getting into the bad state in the first place. You avoid it by seeding the generator.
You should explicitly seed the generator on startup. This avoids some of the problems with calling
RAND_poll
. For some of the problems, see Random Numbers on the OpenSSL wiki.You should occasionally seed the generator. In this case, read from
/dev/urandom
periodically and feed it to the generator withRAND_add
. And add any other entropy you can get your hands on, like your peer's public key or mobile sensor data.According to two papers (here and here), you should add entropy before generating a secret. So you should call
RAND_add
before each call toRAND_bytes
. In this case, you should never get into a bad state.You can also try
RAND_status
. If it returns 0, you should supply it with another block of entropy. The block should be at least 32 bytes. The amount of entropy needed to seed the generator is purposefully hidden. Keep in mind the value changed from 16 to 32 bytes over time, so the thread uses the old value of 16.I suspect
RAND_status
suffers a race in a multithreaded environment, so I would not depend on it. That is, status could change between the call toRAND_status
andRAND_bytes
.In this case, catch the exception, add 32 bytes to the generator and then retry the operation.
RAND_status
will likely return 0 before the exception, and 1 after you add the entropy.But you should not get into this state in the first place.
You should feed your generator any entropy you get your hands on, even less than perfect ones. The more redundancy, the better. Some folks would like to argue about whether to use
/dev/random
versus/dev/urandom
versus/dev/srandom
. I don't really care as long as there's enough entropy - I'm using/dev/random
,/dev/urandom
, peer public keys, time, PIDs, and sensor readings from mobile devices.Don't worry about things like "the attacker can see the peer key" or "sensor data is biased". The entropy will be extracted and the mixer will add it to state so the attacker does not gain an advantage.
I think this is what Gutmann and Griggs call "crypto-numerology".
Suppose you can capture physical events, and suppose you can read from a generator with a crypto primitive that provides or 256-bits of security. Then, suppose you need 32 bytes of data.
There is no difference between the random process giving you 32 bytes or the crypto based generator giving you 32 bytes. For the physical process, the attacker can only guess, so they have a
1 / 2^256
chance of a guess. With a crypto primitive, the attacker has a1 / 2^256
chance of a guess. They are the same...