
Java tutorials home
java.util.Random
Random number generators
XORShift
High quality random
Seeding generators
Entropy
SecureRandom
Random sampling
Random simulations and nextGaussian()
The Java SecureRandom classThe SecureRandom class, housed in the java.security package, provides a dropin replacement to java.lang.Random. But unlike the latter, java.security.SecureRandom is designed to be cryptographically secure. We'll look in more detail below at what this means. First, let's address the question from a simple, practical point of view: when should you use SecureRandom? When to use SecureRandomSecureRandom is typically used in cases where:
On the other hand, it may not be an appropriate generator where CPU time need to generate numbers is a factor that is worth trading for quality of randomness. As a rough guide: SecureRandom is about twenty to thirty times slower than "good mediumquality" generators such as the XORShift or the Numerical Recipes combined generator. CPU usage may be an issue, for example, in:
Properties of SecureRandomWe said that SecureRandom is designed to be cryptographically secure. In practice, this means that the generator has the following properties:
These properties are important in various security applications. The first is important, for eaxmple, if we use the generator to produce, say, a session ID on a web server: we don't want user n to predict user n+1's session ID. Similarly, we don't want a user in an Internet cafe, based on the session ID or encryption key that they are given to access a web site, to be able to predict the value assigned to a previous user on that machine. The other properties are together important when picking, say, a session ID or encryption key, to ensure that any of all the possibly values (or a sufficient proportion of them) can be selected, and we'll take a moment now to consider why. The importance of producing "all values with equal probability"For example, let's say that we want to pick a 128bit AES encryption key. The idea of a strong encryption algorithm such as AES is that in order for an adversary to guess the key by "brute force" (which we assume is the only possible means), they would have to try every single possible key in turn until they hit on the right one. By law of averages, we would expect them to find it after half as many guesses as there are possible keys. A 128bit key has 2^{128} possible values, so on average, they would have to try 2^{127} keys. In decimal 2^{127} is a 39digit number. Or put another way, trying a million million keys per second, it would take 5x10^{15} millennia to try 2^{127} keys. Not even the British government wants to decrypt your party invitations that badly. So with current mainstream technology^{1}, a 128bit key is in principle sufficient for most applications. But these metrics hold true only if our key selection algorithm— i.e. our random number generator— genuinely can pick any of the possible keys. For example, we certainly should not choose the key as follows: // This is WRONG!! Do not do this! Random ranGen = new Random(); byte[] aesKey = new byte[16]; // 16 bytes = 128 bits ranGen.nextBytes(aesKey); The problem here is that the period of java.util.Random is only 2^{48}. Even though we're generating a 128bit key, we will only ever pick from a subset of 2^{48} of the possible keys. Or put another way: an attacker need only try on average 2^{47} keys, and will find our key by trial and error in a couple of days if they try just a thousand million keys per second. And as if that wasn't bad enough, they probably don't even need to try anywhere near 2^{47}: for reasons discussed earlier, there's a good chance that an instance of java.util.Random created within a couple of minutes of bootup will actually be seeded from a about one thousandth of the 2^{48} possible values. This time, HM Sniffing Service doesn't even need expensive hardware to find the secret location of your housewarming party: a trip to Staples will give them all the computing power they need. So as you've probably guessed, our solution to the problem is to use SecureRandom instead: import java.security.SecureRandom; .. Random ranGen = new SecureRandom(); byte[] aesKey = new byte[16]; // 16 bytes = 128 bits ranGen.nextBytes(aesKey); Now, there's a good chance that any of the 2^{128} possible keys will be chosen. Seeding of SecureRandomIn order to provide this property of choosing any seed with "equal" likelihood, (or at least, with no bias that is practically detectable), SecureRandom seeds itself from sources of entropy available from the local machine, such as timings of I/O events. 1. Note that with a quantum computer, the complexity of guessing the key is apparently proportional to the square root of the number of possible keys. Then, guessing the 128bit key at the same rate would take only about 200 days. Written by Neil Coffey. Copyright © Javamex UK 2013. All rights reserved. 