Random number generation depends on a source of entropy such as signals, devices, or hardware inputs. Secure random number generation is also addressed by MSC02-J. Generate strong random numbers.

The java.security.SecureRandom class is widely used for generating cryptographically strong random numbers. According to the java.security file present in the Java Runtime Environment's lib/security folder [API 2013]:

Select the source of seed data for SecureRandom. By default an attempt is made to use the entropy gathering device specified by the securerandom.source property. If an exception occurs when accessing the URL then the traditional system/thread activity algorithm is used.

On Solaris and Linux systems, if file:/dev/urandom is specified and it exists, a special SecureRandom implementation is activated by default. This "NativePRNG" reads random bytes directly from /dev/urandom. On Windows systems, the URLs file:/dev/random and file:/dev/urandom enable use of the Microsoft CryptoAPI seed functionality.

An adversary should not be able to determine the original seed given several samples of random numbers. If this restriction is violated, all future random numbers may be successfully predicted by the adversary.

Noncompliant Code Example

This noncompliant code example constructs a secure random number generator that is seeded with the specified seed bytes:

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

This constructor searches a registry of security providers and returns the first provider that supports secure random number generation. If no such provider exists, an implementation-specific default is selected. Furthermore, the default system-provided seed is overridden by a seed provided by the programmer. Using the current system time as the seed is predictable and can result in the generation of random numbers with insufficient entropy.

Compliant Solution 

Prefer the no-argument constructor of SecureRandom that uses the system-specified seed value to generate a 128-byte-long random number.

byte[] randomBytes = new byte[128];
SecureRandom random = new SecureRandom();
random.nextBytes(randomBytes);

Specifying the exact RNG algorithm and provider can improve portability, perhaps when complying with a design or regulation that mandates a particular algorithm. However, if no arguments are provided, the constructor will provide a default secure RNG.

Applicability

Insufficiently secure random numbers enable attackers to gain specific information about the context in which they are used.

Insecure random numbers are useful in some contexts that do not require security. These are addressed in the exceptions to MSC02-J. Generate strong random numbers.

Bibliography

 


2 Comments

  1. I fully agree with the code and the seeding recommendation in the Compliant Solution.

    The Compliant Solution also specifies:

    "It is also good practice to specify the exact random number generator and provider for better portability"

    I'm not sure about this good practice. For portability it is certainly better to specify no specific algorithm or provider (random bytes are random bytes). I could imagine that there are requirements to use a specific algorithm or provider (i.e. FIPS compliant hardware provider), but in that case the developer must be sure that those are available in the runtime environment. In general I'd keep to the provided code and let the system figure out which random provider is best.

    Note that there are no required SecureRandom algorithms for Java implementations. There must be a default, but that's about it (source: https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl)

    1. Thanks for the advice. I reworded that sentence.