By Erik Costlow-Oracle on Dec 11, 2014
Random numbers are an important part of software systems, especially those that deal with security or encryption. The Java platform offers different types of randomness based on intent, and static typing can further guide that choice for library developers.
This post is intended to explain how the Oracle JDK provides random numbers, to guide their usage:
- Developers building Java software, to use the right randomness in the right place.
- Companies buying or running Java software to understand how to evaluate or control that software.
- System Administrators tuning the security and performance of those systems, understanding why/where/how to make adjustments.
Randomness in the JDK
Java SE provides three mechanisms for generating random numbers based on their usage:
- A fast Random number designed for basic tasks where true randomness is not the main goal. This is useful for things like which shade of color to use, preventing overlap in force-directed layouts, or which picture to show from a list after evaluating demographic information.
- High-concurrency programs may also use ThreadLocalRandom if they value speed over true randomness. This is the same as above but will likely give better performance if simultaneous threads generate pseudo-random numbers at the same time.
- A slower but more random SecureRandom designed for important tasks where the inability to predict numbers is crucial to success. Examples include cases like gambling, scientific sampling, or any cryptographic operations. Although slower than the other two random number generators, its better randomness in many applications.
Having these choices allows developers to make the appropriate decision based on their application.
The Java Platform also allows software operators to override and control this behavior. For example improving true-ness of the Random generator or improving speed of SecureRandom with dedicated hardware.
Security through static typing
Java’s static typing can also enforce that program authors and library users apply the proper Random implementation. The random classes are designed with inheritance, allowing full interoperability across implementations. Both SecureRandom and ThreadLocalRandom inherit from Random, which means that implementations can be swapped or specified:
Random pseudoRandom = new Random(); Random pseudoRandomConcurrent = ThreadLocalRandom.current(); Random secureRandom = new SecureRandom();
For API design, developers can choose to only accept the appropriate version based on their use case. Given that true randomness is crucial to the success of cryptographic operations, it is critical that cryptographic APIs only accept SecureRandom arguments and never the super-class of Random. One example of this is KeyPairGenerator, which helps generate public/private keys that are used by many cryptographic systems. Users can only seed this with true-random values and not pseudo-random values.
KeyPairGenerator.initialize(int keysize, SecureRandom random);
Developers can only call this method by using statically-typed SecureRandom values. The super-type Random PRNG, which might make predictable keys, cannot work. Calling the overloaded KeyPairGenerator.initialize(int keysize) will also use a SecureRandom and is fine, the point here is that static typing prevents other types of Random from being used.
Using the previous example, one could call:
kpg.initialize(4096, (SecureRandom) secureRandom);
Or by specific static typing:
SecureRandom staticEnforcement = new SecureRandom(); kpg.initialize(4096, staticEnforcement);
API designers building secure systems should follow this example of statically typing SecureRandom in method signatures. When vetting secure software, look for usage of Random where a SecureRandom might be more appropriate. The US CERT Java coding guidelines offer additional guidance on evaluating the use of random numbers. Simon Kitching also has a good write-up about Using the SecureRandom Class.
Sources of Randomness
The sources for randomness are listed in the JDK’s security Standard Names documentation, identifying which are blocking or non-blocking. Although some sources rely on entropy pools, SecureRandoms like SHA1PRNG are quite fast once seeded and do not need additional entropy.
Blocking is especially important on Linux systems, where some calls to /dev/random may pause while the system generates a new true-random number. There is a trade-off /dev/urandom device that is non-blocking but somewhat less random.
Within a Java installation, the administrator can adjust various settings through the "JRE/lib/security/java.security" configuration file. That file contains documentation about configuring securerandom.source and securerandom.strongAlgorithms. On Linux systems, the administrator may set their securerandom.source to /dev/random or /dev/urandom accordingly.
Each operating system contains its recommended default value. System Administrators may edit that value, for example if their system has different RNGs or if they have a separate specialized hardware RNG.
JavaMex has a page describing the sources of entropy that Java uses on different operating systems.
Additional information is available in the SecureRandom javadoc.