If you want a cryptographically strong random numbers in Java, you use SecureRandom
. Unfortunately, SecureRandom
can be very slow. If it uses
On Linux, the default implementation for SecureRandom
is NativePRNG
(source code here), which tends to be very slow. On Windows, the default is SHA1PRNG
, which as others pointed out you can also use on Linux if you specify it explicitly.
NativePRNG
differs from SHA1PRNG
and Uncommons Maths' AESCounterRNG in that it continuously receives entropy from the operating system (by reading from /dev/urandom
). The other PRNGs do not acquire any additional entropy after seeding.
AESCounterRNG is about 10x faster than SHA1PRNG
, which IIRC is itself two or three times faster than NativePRNG
.
If you need a faster PRNG that acquires entropy after initialization, see if you can find a Java implementation of Fortuna. The core PRNG of a Fortuna implementation is identical to that used by AESCounterRNG, but there is also a sophisticated system of entropy pooling and automatic reseeding.
According to the documentation, the different algorithms used by SecureRandom are, in order of preference:
Since you asked about Linux, I'm ignoring the Windows implementation, and also SunPKCS11 which is only really available on Solaris, unless you installed it yourself — and then you wouldn't be asking this.
According to those same documentation, what these algorithms use are
SHA1PRNG
Initial seeding is currently done via a combination of system attributes and the java.security entropy gathering device.
NativePRNG
nextBytes()
uses /dev/urandom
generateSeed()
uses /dev/random
NativePRNGBlocking
nextBytes()
and generateSeed()
use /dev/random
NativePRNGNonBlocking
nextBytes()
and generateSeed()
use /dev/urandom
That means if you use SecureRandom random = new SecureRandom()
, it goes down that list until it finds one that works, which will typically be NativePRNG. And that means that it seeds itself from /dev/random
(or uses that if you explicitly generate a seed), then uses /dev/urandom
for getting the next bytes, ints, double, booleans, what-have-yous.
Since /dev/random
is blocking (it blocks until it has enough entropy in the entropy pool), that may impede performance.
One solution to that is using something like haveged to generate enough entropy, another solution is using /dev/urandom
instead. While you could set that for the entire jvm, a better solution is doing it for this specific instance of SecureRandom
, by using SecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
. Note that that method can throw a NoSuchAlgorithmException if NativePRNGNonBlocking, so be prepared to fallback to the default.
SecureRandom random;
try {
random = SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException nsae) {
random = new SecureRandom();
}
Also note that on other *nix systems, /dev/urandom may behave differently.
/dev/urandom
random enough?Conventional wisdom has it that only /dev/random
is random enough. However, some voices differ. In "The Right Way to Use SecureRandom" and "Myths about /dev/urandom", it is argued that /dev/urandom/
is just as good.
The users over on the Information Security stack agree with that. Basically, if you have to ask, /dev/urandom
is fine for your purpose.
Using Java 8, I found that on Linux calling SecureRandom.getInstanceStrong()
would give me the NativePRNGBlocking
algorithm. This would often block for many seconds to generate a few bytes of salt.
I switched to explicitly asking for NativePRNGNonBlocking
instead, and as expected from the name, it no longer blocked. I have no idea what the security implications of this are. Presumably the non-blocking version can't guarantee the amount of entropy being used.
Update: Ok, I found this excellent explanation.
In a nutshell, to avoid blocking, use new SecureRandom()
. This uses /dev/urandom
, which doesn't block and is basically as secure as /dev/random
. From the post: "The only time you would want to call /dev/random is when the machine is first booting, and entropy has not yet accumulated".
SecureRandom.getInstanceStrong()
gives you the absolute strongest RNG, but it's only safe to use in situations where a bunch of blocking won't effect you.
I had a similar problem with calls to SecureRandom
blocking for about 25 seconds at a time on a headless Debian server. I installed the haveged
daemon to ensure /dev/random
is kept topped up, on headless servers you need something like this to generate the required entropy.
My calls to SecureRandom
now perhaps take milliseconds.
You should be able to select the faster-but-slightly-less-secure /dev/urandom on Linux using:
-Djava.security.egd=file:/dev/urandom
However, this doesn't work with Java 5 and later (Java Bug 6202721). The suggested work-around is to use:
-Djava.security.egd=file:/dev/./urandom
(note the extra /./
)