Strong random number generation hangs on Linux machines

Dices making a random number

The code that seemingly hangs the application might look like this:

SecureRandom secureRandom = SecureRandom.getInstanceStrong();
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(4, secureRandom);

String encodedPassword = encoder.encode("my very secret password");

System.out.println(encodedPassword);

Sometimes it runs just fine, but the next time you execute it it just hangs again.

So you fire up the debugger and quickly find out that the code hangs on that “encoder.encode(…)” line.
And since you’re a very brave developer, you even decide to debug BCryptPasswordEncoder‘s class, step-by-step, falling deeper into the rabbit hole… You end up finding the line that seems to hang, located into BCrypt‘s static gensalt() method:

random.nextBytes(rnd);

How is that even possible?

It’s probably…

Maybe you haven’t installed Oracle’s JCE (Java Cryptography Extension)? But then you would probably end up with an exception similar to “java.security.InvalidKeyException:illegal Key Size“.

You quickly dismiss a bug in BCrypt’s implementation. We’re talking about Spring Security here, so if such a bug existed it would have been reported and fixed a while ago!

Nope, it appears the answer is more subtle that that.

Gotcha!

Brace yourself.

Libraries such as BCrypt use SecureRandom to hash and salt, which requires a strong random number generator. The stronger the RNG is, the better!

In the code above, we’ve explicitly asked for a strong instance of SecureRandom. But even when not specifying it, BCrypt requests the default random number generator with this bit of code (from SecureRandom):

for (Provider p : Providers.getProviderList().providers()) {
    for (Service s : p.getServices()) {
        if (s.getType().equals("SecureRandom")) {
            return s.getAlgorithm();
        }
    }
}

If you run that code on your Linux machine, you will notice that the service instance returns “NativePRNG” as the found algorithm.

Now, NativePRNG taps on /dev/random to obtain securely-generated random bytes. In fact, in that /dev folder you should find at least two random number generators: random and urandom. There are major difference between the two of them, though!

Try this: open you terminal and type cat /dev/urandom. You will obtain a fast-scrolling output of what looks like random bytes. Cool, right? Now type cat /dev/random… Well, where did the fast-scrolling random bytes go? Try to move your mouse around: suddenly some additional bytes are added to the output. And now don’t move and stay still. Wait. Wait some more… Nothing happens! No more random bytes are appearing! Why?

True randomness is a very hard thing to obtain. It’s a fantastic topic, but one that’s a little to vast to write about here. So let’s just say this: a computer will have a very hard time generating true random numbers, unless you add some sort of unpredictable noise to the mix. These usually come from the outside. For example, a developer moves his mouse randomly: we never know where and how far he’ll move the pointer, or when he’ll decide to move it. So that’s a good source. You can get other good sources from measured atmospheric noise, random noise picked up by a microphone in a silent room or even… a lava lamp! The point is: life is unpredictable, so it’s a good source of randomness.

The “random” device reads secure random bytes from what is called an “entropy pool“: a sort of store that gathers bytes generated very randomly by the disorder (aka the randomness) of a system. But if the pool is out of truly random bytes, “randomwill block until it gets them. Bummer!
On the other hand “urandom” never blocks: when there are no more bytes in the pool, it falls back to a slightly-degraded random number generation approach. That randomness works on most cases… except maybe when dealing with cryptography and hashing, when we really want to be sure our random number is absolutely random!

Right, so how do we get true secure random numbers then? Ideally we need a “hardware random number generator“. Or a bunch of hired persons that spend their days wiggling a mouse and pressing keys randomly on a keyboard. Whatever suits you best.
A “hardware number generator” is any source in our computer’s hardware that our Linux kernel can count on to generate random noise. Most AMD and Intel processors nowadays include hardware random number generators. So all we need to do is to feed those sources into /dev/random so that we get a constant stream of true random bytes.

Luckily for us such a tool already exists: rngd is a daemon that feeds the entropy pool with as much hardware random data as it can gather! It comes as part of the rng-tools utilities library. Just type the following in a terminal:

sudo apt install rng-tools

Now try to examine the content of /dev/random again: cat /dev/random
Yeah, we’re back in business!

Well, that was a long “Gotcha!”, I’d say! Hopefully, it should save you a few hours of frustration.

Until next time,

Cheers!

Leave A Comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked

This site uses Akismet to reduce spam. Learn how your comment data is processed.