Is SecureRandom.ints() secure?
JavaSecurityRandomJava Problem Overview
It is known that SecureRandom class provide strong cryptographic security for generated random number. java.util.Random
is insecure for the situation which requires cryptographic security. The typical usage of SecureRandom
is:
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
However, I met a case:
SecureRandom random = new SecureRandom();
int number = random.ints();
The method ints()
is inherited from the java.util.Random
class. I am confused when SecureRandom
which is a secure random number generator uses a method inherited from the insecure random number generator, whether it is secure?
Java Solutions
Solution 1 - Java
Yes it is secure.
Code examination of java.util.Random
shows that ints()
creates a spliterator that uses internalNextInt(...)
to generate the random integers. That in turn calls nextInt()
on this
. In the case of java.security.SecureRandom
, nextInt()
is overridden to generate a "secure" random number1.
You can confirm this for yourself by looking at the source code.
1 - Of course, it doesn't actually make sense to call an integer or a sequence of integers "secure". And there are situations where SecureRandom may not have the properties that you require. (It depends on the actual RNG or PRNG implementation used by the class, the quality of the supplied seed or system provided entropy source, and so on.) But SecureRandom::ints() will generate a sequence of integers that has the same properties as if you made a sequence of SecureRandom::nextInt() calls on the same object. If the latter sequence is suitable for your purposes (whatever they are) then so is the former.
Solution 2 - Java
Random.ints()
is a method that returns an IntStream
. An IntStream
is neither secure nor insecure: it's a stream of numbers.
The "security" of the sequence of ints returned by the method depends on the implementation of the method. SecureRandom
generates its "random" values more securely than Random
. They share the same API, and thus you can use either in a given context depending upon your requirements.
So, the fact it inherits from an insecure class is irrelevant to the security: you can reasonably trust that the SecureRandom
class is as secure as the documentation says it is.
Consider an analogy with HashSet
: this makes no guarantees of the iterator ordering; however, LinkedHashSet
, a subclass of HashSet
does guarantee iterator ordering. The guarantee of LinkedHashSet
is consistent with the guarantee of HashSet
, because a specific ordering is one of the possible orderings that could be observed with "no guaranteed ordering" (after all, you have to return the elements in some order).
Similarly, Random
makes no guarantees about the security of the sequence of ints returned; SecureRandom
makes stronger guarantees. But there is no reason why the sequence of ints from a SecureRandom
couldn't also be returned by a Random
, by coincidence.
Solution 3 - Java
Yes, SecureRandom
> provides a cryptographically strong random number generator (RNG).
One important factor for a secure RNG is the seed.
> Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in RFC 4086: Randomness Requirements for Security.
Go ahead and use it. If you are interested in the details, read the JavaDoc which describes the various approaches used by implementations.
Solution 4 - Java
ints method
Yes, it is secure, as long as nextInt()
is secure (for the number of integers retrieved from the stream).
According to the documentation of the Random#ints()
method:
> A pseudorandom int
value is generated as if it's the result of calling the method nextInt()
.
Now in turn, Random#nextInt
:
> The method nextInt
is implemented by class Random
as if by (returning) next(32)
next(int)
is a protected method that you cannot call, but which can be overridden in implementing classes.
Which in turn is implemented as SecureRandom.next(32)
if you use an instance of SecureRandom
rather than Random
:
> Generates an integer containing the user-specified number of pseudo-random bits (right justified, with leading zeros). This method overrides a java.util.Random
method, and serves to provide a source of random bits to all of the methods inherited from that class (for example, nextInt
, nextLong
, and nextFloat
).
So in the end a method of SecureRandom
is called, and if that's secure then the stream of random numbers is secure. Now to be honest, that statement is wrong in the sense that it isn't used for nextBytes
, but it is certainly used for any method that returns number values.
SecureRandom implementation
If you're already sure that the SecureRandom
that you use is secure, then you can stop reading here.
Now you'd think that it would end here, but SecureRandom
by itself does not implement a random bit generator. Instead, it simply depends on a particular service class within the configured provider which implements SecureRandomSpi
(Spi means Service Provider Interface, an abstract class a provider has to implement to deliver secure random data to instances of SecureRandom
). So in the end an invocation of SecureRandomSpi#nextBytes()
will have to be made within SecureRandom#next(int)
to retrieve the actual bits.
As stated for Random#next(int)
other methods that require numbers or streams of numbers should - in the end - all call this particular method. Now if this is indeed the case depends on the implementation of Random
, SecureRandom
. If the result is secure depends on the algorithm and the seeding provided by SecureRandomSpi
, the actual random bit generator that is used.
I've proven above that the result should be really be cryptographically random, assuming that SecureRandom
is cryptographically random. In the end only a full code review for each implementation & version of Java needs to be made to show that it is secure. That's outside of scope for StackOverflow though, you may need support from e.g. Oracle, IBM or Google to retrieve test documents and reviews, or you may perform such a review yourself for a particular implementation, of course. Most of it - if not all of it - is Open Source after all.
Solution 5 - Java
Yes,
the previous solutions are using pseudo-random numbers. SecureRandom
is a cryptographically strong random number generator.
The implementation only differs slightly from the ones before. Frankly speaking, it is a drop-in replacement for Random:
public static void main(String[] args) {
SecureRandom current = new SecureRandom();
// [0, 101)
System.out.println(current.nextInt(101));
System.out.println(current.nextInt(101));
}
For more see Java Random Number Generation.