8

There are a lot of questions asking if a specific initiation of SecureRandom is "good", but I couldn't find a rule of thumb.

What's the best way to create a "good" random SecureRandom?

// Fast
// Is it a good random?
SecureRandom secureRandom = new SecureRandom()?

// Freezes for a few seconds after being used several times - until getting a random enough seed.
// See http://stackoverflow.com/questions/137212/how-to-solve-performance-problem-with-java-securerandom#comment68934647_137212
// Is it a good random?
SecureRandom secureRandom = new SecureRandom(SecureRandom.getSeed(20))?

// Freezes for a very long time. Waited minutes and still no return :(
SecureRandom secureRandom = new SecureRandom.getInstanceStrong()?

Other?
AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277

2 Answers2

5

Basically, the best answer is: you don't know. You'd better leave the choice up to the experts and use new SecureRandom(). This will retrieve the first random number generator by the highest priority provider that has one.

Which providers are present and which one has priority depends on the runtime (IBM and Android also have Java compatible runtimes). The runtime configuration may also differ per operating system, even for the standard JDK.

On an Virtual Machine you SHOULD install the OS specific client toolset of the particular VM manager; this commonly allows the client OS to seed from the host OS. SecureRandom commonly depends on the host to provide the seed or even the random data. If the host however cannot successfully seed itself then the Java runtime won't be able to either and the "random data" created on a virtual host may repeat.

From the JCA documentation:

All Java SE implementations provide a default SecureRandom using the no-argument constructor: new SecureRandom(). This constructor traverses the list of registered security providers, starting with the most preferred provider, then returns a new SecureRandom object from the first provider that supports a SecureRandom random number generator (RNG) algorithm. If none of the providers support a RNG algorithm, then it returns a SecureRandom object that uses SHA1PRNG from the SUN provider.


There is absolutely no need to "seed" the algorithm yourself. Calling getSeed() will try and retrieve a seed from the runtime. This may deplete the randomness pool, just like getInstanceStrong(), resulting in a block of your application and possibly other applications as well until entropy becomes available. The SecureRandom implementations will seed themselves - hopefully in the best way possible - if you don't provide a seed. Beware that the seed provided is mixed into the random pool in most (modern) implementations, which is initially seeded by e.g. the OS; you should not assume that two instances that have been provided the same seed will generate the same random sequence, not even during testing, and not even if you explicitly specify "SHA1PRNG".

If use of new SecureRandom() results in blocking then you need to make sure that your application doesn't use /dev/random directly, depleting the entropy pool. If it doesn't and it still blocks then /dev/random is probably misbehaving.


For retrieving long term key key material you may also use SecureRandom.getInstanceStrong(). You should generally not use this though; SecureRandom should be strong enough for most use cases. If you use the getInstanceStrong() method you may deplete the entropy pool of your OS. Note that on newer systems this is less likely to happen. For instance on Linux both /dev/random and /dev/urandom point to the same pseudo-random number generators.


Preferably you should not use "SHA1PRNG". Even though all runtimes have an implementation, it is not an implementation requirement:

[1] No specific Configuration type, Policy type or SecureRandom algorithm is required; however, an implementation-specific default must be provided.

Note that Android first used an insecure "SHA1PRNG" implementation, which was subsequently replaced by OpenSSL native code. Basically the implementation lied on which RNG was used. The problem is that the algorithm of SHA1PRNG hasn't even been specified by Sun, so it is impossible to rely on any specifics of the algorithm, even if the default implementation seems to be secure.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
0

I believe that unless you have special requirements, all of them are good enough.

The doc for getSeed() says:

This method is only included for backwards compatibility. The caller is encouraged to use one of the alternative getInstance methods to obtain a SecureRandom object, and then call the generateSeed method to obtain seed bytes from that object.

You may of course follow the instructions exactly, but I’m unsure there is a point over your other examples.

I can’t remember where, but I read long ago that it’s preferred to give the algorithm explicitly. So I usually do

SecureRandom.getInstance("SHA1PRNG")

for SHA1 algorithm; PRNG is for pseudo-random number generator. While SHA1 is getting worn for general cryptographic purposes, I am being told it’s still fine for random numbers also when you want to use them for cryptographic keys.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161