Java tutorials home  java.util.Random  Random number generators  XORShift  High quality random  Seeding generators  Entropy  SecureRandom  Random sampling  Random simulations and nextGaussian()

Seeding random number generators (ctd):
looking for entropy

On the previous page, we introduced the problem of finding a random number generator seed. For casual applications, System.nanoTime() will generally return a value that has enough unpredictable bits to seed a generator such as java.util.Random or even the XORShift generator we also mentioned. Using System.nanoTime() almost certainly won't be able to produce any of the 264-1 starting values for the 64-bit XORShift generator, and almost certainly not with equal probability. But for a casual game, it may be good enough.

For more serious applications, we need to find more bits of "true randomness" or entopy. In a moment, we'll see that:

In Java, a practical way to access entropy is to use the SecureRandom class. In some cases we may be able to mix in extra entropy if it is available.

Using SecureRandom to read OS-provided entropy

In practice, modern operating systems help us solve the problem of obtaining entropy. Depending on the machine and environment, there are various sources of entropy potentially available to software. The OS generally "knows" where it can collect entropy from. So it collects entropy "as it goes along" and exposes it to the programmar via an API call or similar. On Windows, this is generally the CryptGenRandom() API call; on UNIX-like systems such as Linux, Solaris and Mac OS, by reading from the /dev/random device file.

In Java, the SecureRandom class then acts as a wrapper to this OS-provided entropy:

  • the Java SecureRandom class effectively provides access to the OS-generated entropy stream where available, also mixing it in with some (lower-quality) sources of entropy, such as names of files in the temp directory;
  • if your program can easily generate some extra entropy, it generally "does no harm" to mix in this extra entropy, and SecureRandom provides a means to do this;
  • then, SecureRandom can generate high-quality seeds (and indeed, high-quality random numbers in general, albeit more slowly than with some other generators).

To obtain a series of bytes of entropy, we call SecureRandom.getSeed(), having first created an instance of SecureRandom. By default, at least in Sun's implementation, SecureRandom.generateSeed() is effectively a wrapper around the natively available source of entropy, if one is available. If the generator we are seeding allows us to use the byte array directly, then we're home and dry. If the generator requires, say, a long value as its seed, we need to do a bit of conversion. In this case, we can use a ByteBuffer to help us:

public long getLongSeed() {
  SecureRandom sec = new SecureRandom();
  byte[] sbuf = sec.generateSeed(8);
  ByteBuffer bb = ByteBuffer.wrap(sbuf);
  return bb.getLong();
long seed = getLongSeed();
Random ranGen = new XORShiftRandom(seed);

When should you use SecureRandom.generateSeed()?

In general, use SecureRandom.generateSeed() to seed "non-casual" random number generators where it's important that the generator's starting point is any of the possible values. Typical applications are cryptography, simulations (and other scientific uses), or other applications where high-quality randomness is important, such as gambling games where money is involved.

In general, you would use SecureRandom.generateSeed() in conjunction with a high-quality generator. In fact, our example of using it to seed a generator with a 264-1 period is a little unrealistic. If we're happy with an XORShift generator, we'll generally be happy seeding it from System.nanoTime().

The following should be borne in mind:

  • in the worst case, the call SecureRandom.generateSeed() may block until the required entropy has been generated (i.e. enough "random events" such as mouse movements and arrival of disk/network packets have occurred to generate the required entropy);
  • you should consider bits of entropy as a "valuable, shared resource"— if you request entropy faster than it is generated, then your application will block, and so potentially will other applicatons also requesting entropy.

Usually these constraints aren't too much of a problem: a single high-quality generator seeded with a few bytes of entropy should last the lifetime of a typical application.

Next: more about SecureRandom

On the next page, we look at the SecureRandom class for random number generation, and typical cases of when to use it.

comments powered by Disqus

Written by Neil Coffey. Copyright © Javamex UK 2013. All rights reserved.