Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SecureRandom safe seed in Java

Is this piece of code safe?

 SecureRandom randomizer = new SecureRandom(String.valueOf(new Date().getTime()).getBytes());

Is this the right way to instance the seed of secure random?

like image 437
Jordi P.S. Avatar asked Sep 03 '12 13:09

Jordi P.S.


People also ask

What is seed in SecureRandom?

The setSeed() method of java. security. SecureRandom class is used to reseeds this random object. The given seed supplements, rather than replaces, the existing seed.

Is Java SecureRandom secure?

ints methodYes, it is secure, as long as nextInt() is secure (for the number of integers retrieved from the stream). According to the documentation of the Random#ints() method: A pseudorandom int value is generated as if it's the result of calling the method nextInt() .

What is SecureRandom in Java?

public class SecureRandom extends Random. This class provides a cryptographically strong random number generator (RNG). A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9. 1.

Is SecureRandom cryptographically secure?

Additionally, SecureRandom must produce non-deterministic output. Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong.


3 Answers

No, you should avoid the SecureRandom(byte[]) constructor. It is both unsafe and non-portable.

It is non-portable because it behaves differently on Windows vs. other operating systems.

On most OSes, the default algorithm is "NativePRNG", which obtains random data from the OS (usually "/dev/random") and ignores the seed you provide.

On Windows, the default algorithm is "SHA1PRNG", which combines your seed with a counter and computes a hash of the result.

This is bad news in your example, because the input (the current UTC time in milliseconds) has a relatively small range of possible values. For example if an attacker knows that the RNG was seeded in the last 48 hours, they can narrow the seed down to less than 228 possible values, i.e. you have only 27 bits of entropy.

If on the other hand you had used the default SecureRandom() constructor on Windows, it would have called the native CryptoGenRandom function to get a 128-bit seed. So by specifying your own seed you have weakened the security.

If you really want to override the default seed (e.g. for unit testing) you should also specify the algorithm. E.g.

SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed("abcdefghijklmnop".getBytes("us-ascii"));

See also How to solve performance problem with Java SecureRandom?
and this blog post: http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/

like image 82
finnw Avatar answered Sep 22 '22 10:09

finnw


I think it is best to let the SecureRandom seed itself. This is done by calling nextBytes immediately after it's creation (calling setSeed will prevent this).

final byte[] dummy = new byte[512];
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.nextBytes(dummy);

You want to use SHA1PRNG because it guarantees a fast non-blocking implementation even on Linux, where the default is not.

like image 26
user9397757 Avatar answered Sep 21 '22 10:09

user9397757


The code is reasonably safe because it doesn't just use the seed given to seed the randomizer.

Its not much more random than just using.

SecureRandom randomizer = new SecureRandom();
like image 45
Peter Lawrey Avatar answered Sep 23 '22 10:09

Peter Lawrey