Cryptographically Secure Random Numbers in Java

The Random Class

Most people wanting to generate random numbers in Java do something similar to the following:

public static void main(String[] args) {
  Random generator = new Random();
  int randomnumber = generator.nextInt(5) + 1;
  System.out.println("Dice rolled: " + randomnumber);
}

This is perfectly fine for a simple dice rolling application where there isn’t going to be much effort put into cracking it. For example in this application the only real reason you would bother cracking it would be to show off a neat party trick to your geeky friends. No doubt though the effort wouldn’t be worth it.

Java states that the Random class and its subclasses must produce predictable results when seeded with the same data. This however is not why this is insecure, and it is useful when testing. The reason that this class is predictable though is the way in which it is seeded. The Random class, in the absence of a seed in its constructor it will seed its random number generator with the current time in milliseconds. This means that if somebody knows the time that the Random object was seeded and has several consecutive bytes of output then they can reasonably predict the next numbers. Once somebody has discovered the seed for the generator all number produced from it can be seen as compromised.

The SecureRandom Class

The SecureRandom class is different, it again uses algorithms that when seeded will produce predictable results, but the algorithm is much more complex. It uses a digest algorithm such as SHA-1 on the seed and a counter to generate random data. SHA-1 is much more costly than the simple algorithm used in the Random class and as such it is much harder to brute force.

Its true strength however lies in the method in which it is seeded. The SecureRandom class is seeded using true random data gathered by the operating system. This is data gathered by the OS from sources of true randomisation, such as mouse movements, network packet arrival times, IO statistics and interrupts. On Linux the data is gathered from /dev/random and on Windows via the CryptGenRandom() call in Windows.

When using SecureRandom though you should be aware of a few things:

  • The more random numbers some can get a hold of the more likely they can figure out the seed. You should either throw away the SecureRandom object every now and then or reseed it. Keeping in mind the next point though.
  • The seeding the generator takes entropy out of the system, if it cannot get any entropy it will block until the system has some. This means if you’re reseeding the generator too often your program will hang along with anything else on the system requiring entropy.
  • Don’t seed the SecureRandom class yourself, unless you are 100% absolutely sure you are seeding it with purely random data, or you are testing and need repeatable results. Whatever you do, don’t let your testing code leak into a production system.

How to decide

Generally when you’re coding you don’t need secure random numbers. For example if you’re writing a number guessing game, or a quiz generating program then high quality random numbers aren’t required. It should be noted though that if money is involved people will often go to greater lengths and a more secure generator will be required, such as in a slot machine.

Again generally if what you are generating is a security token of some sort then you will need a secure generator. For example a session id, a one time password or an encryption key. The exception here is a salt for a password, salts can be generated using predictable entropy sources, even a simple time stamp would work here (especially if your also storing the time stamp to measure password expiry).

Random Thought: For those of you who don’t know Bruce Schneier is the Chuck Norris of cryptography.