If you want a cryptographically strong random number in Java, you use SecureRandom
. Unfortunately, SecureRandom
can be very slow. If it uses /dev/random
on Linux, it can block waiting for sufficient entropy to build up. How do you avoid the performance penalty?
Has anyone used Uncommon Maths as a solution to this problem?
Can anybody confirm that this performance problem has been solved in JDK 6?
I had a similar problem with calls to
SecureRandom
blocking for about 25 seconds at a time on a headless Debian server. I installed thehaveged
daemon to ensure/dev/random
is kept topped up, on headless servers you need something like this to generate the required entropy. My calls toSecureRandom
now perhaps take milliseconds.Many Linux distros (mostly Debian-based) configure OpenJDK to use
/dev/random
for entropy./dev/random
is by definition slow (and can even block).From here you have two options on how to unblock it:
Option 1, Improve entropy
To get more entropy into
/dev/random
, try the haveged daemon. It's a daemon that continuously collects HAVEGE entropy, and works also in a virtualized environment because it doesn't require any special hardware, only the CPU itself and a clock.On Ubuntu/Debian:
On RHEL/CentOS:
Option 2. Reduce randomness requirements
If for some reason the solution above doesn't help or you don't care about cryptographically strong randomness, you can switch to
/dev/urandom
instead, which is guaranteed not to block.To do it globally, edit the file
jre/lib/security/java.security
in your default Java installation to use/dev/urandom
(due to another bug it needs to be specified as/dev/./urandom
).Like this:
Then you won't ever have to specify it on the command line.
Note: If you do cryptography, you need good entropy. Case in point - android PRNG issue reduced the security of Bitcoin wallets.
The problem you referenced about
/dev/random
is not with theSecureRandom
algorithm, but with the source of randomness that it uses. The two are orthogonal. You should figure out which one of the two is slowing you down.Uncommon Maths page that you linked explicitly mentions that they are not addressing the source of randomness.
You can try different JCE providers, such as BouncyCastle, to see if their implementation of
SecureRandom
is faster.A brief search also reveals Linux patches that replace the default implementation with Fortuna. I don't know much more about this, but you're welcome to investigate.
I should also mention that while it's very dangerous to use a badly implemented
SecureRandom
algorithm and/or randomness source, you can roll your own JCE Provider with a custom implementation ofSecureRandomSpi
. You will need to go through a process with Sun to get your provider signed, but it's actually pretty straightforward; they just need you to fax them a form stating that you're aware of the US export restrictions on crypto libraries.I haven't hit against this problem myself, but I'd spawn a thread at program start which immediately tries to generate a seed, then dies. The method which you call for randoms will join to that thread if it is alive so the first call only blocks if it occurs very early in program execution.
Something else to look at is the property securerandom.source in file lib/security/java.security
There may be a performance benefit to using /dev/urandom rather than /dev/random. Remember that if the quality of the random numbers is important, don't make a compromise which breaks security.
You should be able to select the faster-but-slightly-less-secure /dev/urandom on Linux using:
However, this doesn't work with Java 5 and later (Java Bug 6202721). The suggested work-around is to use:
(note the extra
/./
)