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 theSecureRandom
’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.