ovunccetin ovunccetin - 5 months ago 22x
Java Question

SecureRandom with NativePRNG vs SHA1PRNG

I need to generate cryptographically strong random numbers and byte arrays. For this purpose, I'm using Java's

class. But I'm not sure to choose which PRNG algorithm in terms of their cryptographic strength.

Which of the following instances generates a more unpredictable numbers? Or are they equal?

SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")

Moreover, we are able to generate these instances with "SUN" provider (e.g.
SecureRandom.getInstance("SHA1PRNG", "SUN")
). Do this make a difference?

Thanks in advance.


With random number generators it is always hard to say which is best. Linux and most Unixes have a pretty well thought out random number generator, so it doesn't hurt to use /dev/random or /dev/urandom, i.e. "NativePRNG". Problem with using /dev/random is that it blocks until enough entropy is available. So I would advice against it unless you've got some special requirements with regards to key generation.

"SHA1PRNG" uses a hash function and a counter, together with a seed. The algorithm is relatively simple, but it hasn't been described well. It is generally thought of to be secure. As it only seeds from one of the system generators during startup and therefore requires fewer calls to the kernel it is likely to be less resource intensive - on my system it runs about 9 times faster than the "NativePRNG" (which is configured to use /dev/urandom). Both seem to tax only one core of my dual core Ubuntu laptop (at a time, it frequently switched from one core to another, that's probably kernel scheduling that's which is to blame). If you need high performance, choose this one, especially if your /dev/urandom is slow.

Personally I would try and refrain from specifying any random generator at all. I would simply go for the empty argument constructor: new SecureRandom() and let the system choose the best random number generator. You can use the new configurable SecureRandom.getInstanceStrong() in Java 8 if you have any specific requirements for e.g. long term key generation. Don't cache instances of SecureRandom, just let them seed themselves initially and let the VM handle them. I did not see a noticeable difference in operation.

In general it's not a good idea to specifically specify a provider. Specifying a provider may hurt interoperability; not every Java runtime may have access to the SUN provider for instance. It also makes your application less flexible at runtime, i.e. you cannot put a provider higher in the list and use that instead.

Only specify a provider if you are dependent on one of the features that it supplies. For instance, you might want to specify a provider if you have a specific hardware device that generates the randoms, or a cryptographic library that has been FIPS certified. It's probably a good idea to make the algorithm/provider a configuration option for your application if you have to specify a provider.

Slightly off topic: when not to use SecureRandom:

As a general warning I strongly advice against using the random number generator for anything other than random number generation. Even if you can seed it yourself and even if you choose Sun's SHA1PRNG, don't count on being able to extract the same sequence of random numbers from the random number generator. So do not use it for key derivation from passwords, to name one example.

If you do require a repeating sequence then use a stream cipher and use the seed information for the key and IV. Encrypt plaintext consisting of zeros to retrieve the key stream of pseudo random values. Alternatively you could use a extendable-output function (XOF) such as SHAKE128 or SHAKE256 (where available).

Obviously, for very high speed operation that doesn't require security, don't use SecureRandom; it won't be as fast as other deterministic random number generators such as those based upon the Mersenne Twister algorithm.