views:

1035

answers:

7

Our team is using a SecureRandom to generate a list of key pairs (the SecureRandom is passed to a KeyPairGenerator). We cannot agree on which of the following two options to use:

  1. Create a new instance every time we need to generate a key pair

  2. Initialize a static instance and use it for all key pairs

Which approach is generally better and why?

ADDED: My gut feeling is that the second option is more secure. But my only argument is a theoretical attack based on the assumption that the pseudorandomness is derived from the current timestamp: someone may see the creation time of the key pair, guess timestamps in the surrounding time interval, compute the possible pseudorandom sequences, and obtain the key material.

ADDED: My assumption about determinism based on a timestamp was wrong. That's the difference between Random and SecureRandom. So, it looks like the answer is: in terms of security it doesn't really matter.

+1  A: 

Why would you want to create a new instance every time? It's not like that would be more random. I think it would be best to initialize once and use it for all pairs.

Jorn
Given modern gc impls, I know it wouldn't affect performance at all. But the question is would it be *less* random then?
ngn
The randomization doesn't decline over extended use. It is just that you are giving an attacker "time" to find your first (only?) seed. The opposite option, reseeding every time, is generally too expensive.
Matthew McCullough
+3  A: 

Initialize a static instance and use it for all key pairs. It won't be any more or less random.

Mitch Wheat
I have a reason to believe that it would actually be more random, but I'm waiting for argument-backed replies to verify or refute my theory. Thanks for the quick reply :)
ngn
How about you put forward your argument for why you think it is?
Mitch Wheat
If you want true randomness, then you need a non-deterministic source. There's a link on SO, somewhere...
Mitch Wheat
... adding my argument to the question's text.
ngn
+5  A: 

Unlike the java.util.Random class, the java.security.SecureRandom class must produce non-deterministic output on each call. What that means is, in case of java.util.Random, if you were to recreate an instance with the same seed each time you needed a new random number, you would essentially get the same result every time. However, SecureRandom is guaranteed to NOT do that - so, creating a single instance or creating a new one each time does not affect the randomness of the random bytes it generates. So, from just normal good coding practices view point, why create too many instances when one will do?

Gowri
Please, please don't use this as justification to use the same PRNG. The docs are ambiguous, and if it's _wrong_, you just made cracking all your keys as easy as figuring out the seed to the PRNG.
Nick Johnson
+3  A: 

I would not rely on SecureRandom to be anything other than a cryptographically secure PRNG. The complete quote that Gowri is using from the javadocs is:

Additionally, SecureRandom must produce non-deterministic output and therefore it is required that the seed material be unpredictable and that output of SecureRandom be cryptographically strong sequences as described in RFC 1750: Randomness Recommendations for Security.

It's less than clear from this what the real expectation is - RFC 1750 details the use of hardware to enhance random number generation, but the javadocs say "therefore it is required that the seed material be unpredictable", which would seem to contradict this.

The safest assumption to work on is that your implementation of SecureRandom is simply a cryptographically-secure PRNG, and therefore that your keys are no more secure than the random seed that you use. Thus, initializing a new SecureRandom with a new (unique, truly random) seed for each key would be the safest bet.

Nick Johnson
+2  A: 

Once should be enough. My experience has also been that initializing SecureRandom type generators can sometimes be slow as well (due to how randomness is achieved), so you should take that into consideration.

Alex Miller
Alex, as I tacked on to some other responses below, wouldn't you want to reseed occasionally so that attackers don't have "unlimited" time to try to discover your seed?
Matthew McCullough
Matthew, I think periodic reseeding makes sense.
Alex Miller
+3  A: 

Every SecureRandom generation is seeded from some entropy pool. Depending on the OS used, this might be the entropy pool maintained by the OS like /dev/random on Linux, or might be something that the JVM cooks up. In some earlier implementations, the Sun JVM used to spawn a number of threads and use their timing data to create the seed. Creating a new SecureRandom on every call might cause slow down of the application since creation of the seed might be blocking. Its better to reuse the a statically created instance, but make sure to reseed it after a fixed number random bytes are extracted from it. You may want to create a wrapper over a securerandom which counts the number of bytes extarcted in nextBytes or generateSeed call and after a number of bytes, reseeds the internal securerandom by using system entropy pool. This however is not possible on Java on Linux since the SecureRandom you get from new SecureRandom() is nothing but a wrapper on /dev/random and every call for nextBytes or generateSeed actually drains the OS entropy pool. On Linux and Solaris, its better to use a JCE provider for SecureRandom creation.

Many folks are wondering why to reseed every so often. It isn't because the numbers get less random. It is because the longer you use the PRNG without reseeding, you are giving a potential attacker that same amount of time to try and brute-force find your seed. While I agree that you should reseed periodically, it can be on a modest interval (hours to a day?), not _every_ time.
Matthew McCullough
+2  A: 

For SecureRandom you would want to consider occasionally reseeding (using system entropy in most cases) via a call like so:

mySecureRandom.setSeed(mySecureRandom.generateSeed(someInt));

so as to give a potential attacker something less than unlimited time to discover your key.

There's some great writeups about this consideration at the Justice League blog.

Matthew McCullough