How to deal with a slow SecureRandom generator?

后端 未结 17 1235
时光说笑
时光说笑 2020-11-22 11:56

If you want a cryptographically strong random numbers in Java, you use SecureRandom. Unfortunately, SecureRandom can be very slow. If it uses

17条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-11-22 12:39

    According to the documentation, the different algorithms used by SecureRandom are, in order of preference:

    • On most *NIX systems
      1. NativePRNG
      2. SHA1PRNG
      3. NativePRNGBlocking
      4. NativePRNGNonBlocking
    • On Windows systems
      1. SHA1PRNG
      2. Windows-PRNG

    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.


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

提交回复
热议问题