I’ve written about several SecureRandom implementations in the past. While analyzing the default SecureRandom implementation in IBM JCE (v1.7) on *nix, I came across several weaknesses. IBM recently released a patch to fix the issues. Let’s take a look at how this SecureRandom implementation works as well as the issues that were recently patched.
Note that the description below is for the unpatched version of IBMSecureRandom. I have not analyzed the latest version that fixes the issues.
On *nix installations of the IBM JRE, IBMJCE is the only default crypto provider that includes SecureRandom implementations. The default SecureRandom implementation in the IBMJCE is IBMSecureRandom. If it happens to not be the default, the implementation can be instantiated using:
This implementation of SecureRandom can be seeded using two different mechanisms as discussed below:
The output of the IBMSecureRandom PRNG is generated using applications of the MD5 hash function. Although MD5 is not considered a secure hash function anymore since it is not collision resistant, use of MD5 here is probably okay because pre-image resistance has not yet been broken in MD5.
However, the way in which MD5 is used here is insecure. The PRNG essentially outputs 8 bytes of its internal state and then hashes the entire internal state using MD5. Therefore, an attacker who can see the PRNG’s output sees half of the PRNG’s internal state. For example, I observed the following output generated by the given state:
An attacker that sees the PRNG’s output would only need to brute force 64 bits of the internal state to predict all future outputs of the PRNG.
Another potential problem with using MD5 here is that the internal state of the PRNG is only 128 bits, which is not acceptable for many scenarios. For example, if you were to shuffle a deck of cards using this PRNG, you would only get 2128 possible card shuffles. However, there are actually 52! – or approximately 2226 possible card shuffles. Many PRNGs aren’t acceptable for shuffling decks of cards for this reason; however, a 128-bit PRNG state is not acceptable for a lot of applications.
If generateSeed() is called, the resulting seed is generated using operations performed on the output of java.util.Random seeded with the system time. Therefore, these seeds are potentially predictable.
Here’s a summary of the main security issues that I discovered:
If your application relies on the unpredictability of outputs from an unpatched version of this implementation (e.g. if you use it to generate session identifiers, passwords, cryptographic keys, etc.), then you have a problem.
Note that some other JCE providers also use IBMSecureRandom for various purposes. So, the issues in the unpatched IBMSecureRandom may impact other JCE providers as well. If you have the IBMJCE provider enabled in your application (even if you’re not using IBMSecureRandom explicitly), make sure that you apply the latest patch from IBM as soon as possible.
What are the lessons learned here? Secure pseudo-random number generation is hard. Even widely used pseudo-random number generators from reputable vendors can contain security issues. If you rolled your own pseudo-random number generator without help from cryptography experts, assume that it’s insecure. If you are using a pseudo-random number generator provided by an OS vendor or a crypto library, don’t just assume that it’s secure. Ask the vendor if the implementation has been reviewed by a third party. Ensure that any third-party reviews didn’t just involve performing statistical analysis on the outputs of the PRNG. The actual implementation details need to be analyzed.