Superziyi Superziyi - 6 months ago 37
Java Question

SecureRandom.getInstance("SHA1PRNG", "SUN") always blocking while new SecureRandom() is not?

I'd like to consult some question on the common myth of SecureRandom in Java, on security vs. performance tradeoff.

I've been researching on the Internet for a while and I've put the following information together. I'd like people here help me confirm what I got and hopefully get some ideas on what to actually choose for implementation.

Basically here are some most popular and thorough articles for SecureRandom:

Proper use of Java's SecureRandom:
http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/

Issues when using Java's SecureRandom:
http://www.cigital.com/justice-league-blog/2014/01/06/issues-when-using-java-securerandom/

Using the SecureRandom class:
http://moi.vonos.net/java/securerandom/

And, Sun's official "confession" of bug/confusion and a proposed release in Java 8:
http://openjdk.java.net/jeps/123

Now that Java 8 is out, I am honestly not sure how better this actually been fixed, by just looking at the documentation:
http://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html

So after all, this is what I got (please help me to see if I got them sorted):

People like Amit Sethi suggests using specified instantiation like: SecureRandom sr3 = SecureRandom.getInstance("SHA1PRNG", "SUN"), where in reality, Sun tells us that this will end up always reading from /dev/random(???), which means it can be potentially blocking for EVERY call. As opposed to if you use new SecureRandom() it will then always read from /dev/urandom unless generateSeed() is called. See

http://bugs.java.com/view_bug.do?bug_id=6202721

Does that mean "new SecureRandom()" is still preferred in current Java? Not many other documenation I found state the above point explicitly so I want to know if that is still true?

Now if "new SecureRandom()" is the choice and will lead to never blocking call, then I think what I should do for periodic reseeding would be:

Make SecureRandom a static instance in the class and let another Executor thread periodically call generateSeed() on it, thus even though the call is blocking, it's not affecting my main request handling thread in my application. Does that sound like a good way doing it?

Really appreciate any Java and crypto experts to shed some light on this issue here.
Thanks!

Edit:
Another useful thread here, seems to back up my guess: https://bugs.openjdk.java.net/browse/JDK-4705093

Answer

EDIT : First of all; if /dev/random or /dev/urandom blocks it makes sense to first try and fix that particular issue. The solutions below are about trying to fix the SecureRandom in Java itself, so it is less dependent on those special devices.


Make SecureRandom a static instance in the class and let another Executor thread periodically call generateSeed() on it, thus even though the call is blocking, it's not affecting my main request handling thread in my application. Does that sound like a good way doing it?

No, you should in that case use nextBytes() as the internal call generateSeed() uses the original supplier of seed information. In other words, you could as well create a separate instance of SecureRandom. Note that whenever you have a SecureRandom instance with a high enough state and a good backing algorithm it is not needed to reseed often (as it is very unlikely to create a cycle). If you ever require higher entropy, generate a new random class each time or use a random retrieved using SecureRandom.getInstanceStrong().

Using the default new SecureRandom() is probably best. Normally you should always supply the precise algorithm name for cryptographic algorithms (e.g. "AES/CBC/PKCS5Padding") but for secure random functionality it is better to let the system figure out which algorithm is best. If you want to change anything, change it through the command line constructs and make sure that /dev/urandom is available on Unix systems.

If you still have issues with blocking, then create a central, system seeded SecureRandom. Create new seed material using nextBytes() and supply this to a new SecureRandom using the SecureRandom(byte[] seed) constructor. This method should only be used if new SecureRandom() fails to handle the situation.

Even though supplying the initial seed is now explicit by using a constructor, the constructor itself does not guarantee that it is solely used for seeding the RNG. It's however likely that it is the case, so it is less likely to block. SecureRandom is thread safe so you don't need to synchronize access to it.

Using the new Java 8 SecureRandom.getInstanceStrong() is more likely to block. I presume that they have added that to make the default instances non-blocking. RSA key pair generation usually wants a lot of entropy, so it is likely that instances returned do use blocking calls to /dev/random.

All in all, using SecureRandom for special cases is still rather mucky. Fortunately this is only an issue for a very limited amount of use cases.