How to solve slow Java `SecureRandom`?

2018-12-31 19:54发布

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?

17条回答
柔情千种
2楼-- · 2018-12-31 20:16

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.

查看更多
柔情千种
3楼-- · 2018-12-31 20:18

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:

  1. Improve entropy, or
  2. Reduce randomness requirements.

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:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

On RHEL/CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

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:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

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.

查看更多
公子世无双
4楼-- · 2018-12-31 20:18

The problem you referenced about /dev/random is not with the SecureRandom 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 of SecureRandomSpi. 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.

查看更多
低头抚发
5楼-- · 2018-12-31 20:18

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.

查看更多
刘海飞了
6楼-- · 2018-12-31 20:19

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.

查看更多
若你有天会懂
7楼-- · 2018-12-31 20:20

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 /./)

查看更多
登录 后发表回答