how to handle low_entropy exception of crypto:stro

2019-05-10 07:55发布

问题:

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.

回答1:

how to handle low_entropy exception of crypto:strong_rand_bytes(N)?

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 with RAND_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 to RAND_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 to RAND_status and RAND_bytes.


May throw exception low_entropy in case the random generator failed due to lack of secure "randomness".

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.


strong_rand_bytes(N) ... I guess a fallback to just rand_bytes(N) ...

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 a 1 / 2^256 chance of a guess. They are the same...