SecureRandom

The JDK includes a class, java.util.Random, that implements a PRNG. Although it’s fine for light-duty use, it has the following shortcomings:

  • It uses an algorithm that produces a predictable sequence of numbers.

  • If you don’t give Random a seed value, it uses the value of the system clock. This is a predictable seed. Let’s say that you create a random number in order to create a cryptographic key. If an attacker knows when you created the random number, even approximately, he or she can guess at likely values of the random number seed. With a relatively small amount of guessing, the attacker can guess which random number seed you’ve used. From this, the attacker can generate the same supposedly random cryptographic key that you just generated. Now the attacker can impersonate you or read your secret messages.

A stronger PRNG, java.security.SecureRandom, was introduced in JDK 1.1. This class is based around a message digest. SecureRandom uses the SHA-1 (Secure Hash Algorithm) message digest algorithm, which produces a 20-byte digest. Here’s how it works:

  • The SecureRandom is created using a seed. The seed value is digested, and the resulting value is stored as part of the SecureRandom’s internal state. An internal counter is initialized to zero.

  • Every time SecureRandom needs to create more pseudo-random numbers, the message digest is updated with the internal state and the counter, which is incremented. This data is digested and returned as the new pseudo-random data.

Because of the irreversible nature of the message digest, it’s very hard to predict the past and future values of the PRNG even if you know its present output.

In practice, you don’t have to worry about the details. Just create a SecureRandom instance and call its nextBytes() method to get pseudo-random data. In the example that follows, a SecureRandom is used to generate 100 bytes of pseudo-random data:

SecureRandom sr = new SecureRandom();
byte[] pseudoRandom = new byte[100];
sr.nextBytes(pseudoRandom);

SecureRandom provides two constructors:

public SecureRandom()

This constructor creates a new SecureRandom and initializes it with automatically generated seed data. This process is called self-seeding and is discussed in the next section.

public SecureRandom(byte[] seed)

This constructor takes the given seed data and uses it to initialize a new SecureRandom instance.

If your application collects truly random data, it can be used to update a SecureRandom’s seed using setSeed() .

public synchronized void setSeed(byte[] seed)

This method updates the internal state of the SecureRandom with a new set of random seed data. The new data does not replace the original seed, but supplements it.

When you need pseudo-random data, call nextBytes() .

public synchronized void nextBytes(byte[] bytes)

This method fills the given byte array with pseudo-random data.

Get Java Cryptography now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.