The **SecureRandom** class, housed in the `java.security` package, provides
a drop-in 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`?

`SecureRandom` is typically used in cases where:

- random numbers are generated for
**security**related purposes, such as generating an encryption key or session ID (see below); - or, more generally,
**high-quality randomness**is important and it is**worth consuming CPU**(or where CPU consumption isn't an issue) to generate those high-quality random numbers.

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 medium-quality" generators such as the XORShift or the
*Numerical Recipes* combined generator.

CPU usage may be an issue, for example, in:

- a
**simulation**or**Monte Carlo experiment**where a very large quantity of numbers needs to be generated quickly; - where a moderate quantity of numbers needs to be generated
but where there are
**"better things to spend the CPU time on"**(e.g. a non-gambling game where the quality of randomness isn't crucial); - a
**multi-user environment**where a moderate quantity of numbers needs to be generated but with minimal impact on other processes.

We said that `SecureRandom` is designed to be **cryptographically secure**.
In practice, this means that the generator has the following properties:

- given only a number produced by the generator, it is (to all intents and purposes)
**impossible to predict previous and future numbers**; - the numbers produced contain
**no known biases**; - the generator has a
**large period**(in Sun's standard implementation, based on the 160-bit SHA1 hash function, the period is 2^{160}); - the generator can
**seed itself at any position within that period with equal probability**(or at least, it comes so close to this goal, that we have no practical way of telling otherwise).

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.

For example, let's say that we want to pick a 128-bit 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 128-bit key has 2^{128} possible values, so on average, they would have to try
2^{127} keys.
In decimal 2^{127} is a 39-digit 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 128-bit 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 128-bit 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

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.

In 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 128-bit key at the same rate would take only about 200 days.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.