security. SecureRandom class: This class provides a cryptographically strong random number generator (RNG). A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.
util. Random are not cryptographically secure. Consider instead using SecureRandom to get a cryptographically secure pseudo-random number generator for use by security-sensitive applications. However, the way the code is currently using java.
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() .
No, a SecureRandom instance does not guarantee unique results.
The standard Oracle JDK 7 implementation uses what's called a Linear Congruential Generator to produce random values in java.util.Random
.
Taken from java.util.Random
source code (JDK 7u2), from a comment on the method protected int next(int bits)
, which is the one that generates the random values:
This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and described by Donald E. Knuth in The Art of Computer Programming, Volume 3: Seminumerical Algorithms, section 3.2.1.
Hugo Krawczyk wrote a pretty good paper about how these LCGs can be predicted ("How to predict congruential generators"). If you're lucky and interested, you may still find a free, downloadable version of it on the web. And there's plenty more research that clearly shows that you should never use an LCG for security-critical purposes. This also means that your random numbers are predictable right now, something you don't want for session IDs and the like.
The assumption that an attacker would have to wait for the LCG to repeat after a full cycle is wrong. Even with an optimal cycle (the modulus m in its recurrence relation) it is very easy to predict future values in much less time than a full cycle. After all, it's just a bunch of modular equations that need to be solved, which becomes easy as soon as you have observed enough output values of the LCG.
The security doesn't improve with a "better" seed. It simply doesn't matter if you seed with a random value generated by SecureRandom
or even produce the value by rolling a die several times.
An attacker will simply compute the seed from the output values observed. This takes significantly less time than 2^48 in the case of java.util.Random
. Disbelievers may try out this experiment, where it is shown that you can predict future Random
outputs observing only two(!) output values in time roughly 2^16. It takes not even a second on a modern computer to predict the output of your random numbers right now.
Replace your current code. Use SecureRandom
exclusively. Then at least you will have a little guarantee that the result will be hard to predict. If you want the properties of a cryptographically secure PRNG (in your case, that's what you want), then you have to go with SecureRandom
only. Being clever about changing the way it was supposed to be used will almost always result in something less secure...
A random has only 48 bits where as SecureRandom can have upto 128 bits. So the chances of repeating in securerandom is very small.
Random uses the system clock
as the seed/or to generate the seed. So they can be reproduced easily if the attacker knows the time at which the seed was generated. But SecureRandom takes Random Data
from your os
(they can be interval between keystrokes etc - most os collect these data store them in files - /dev/random and /dev/urandom in case of linux/solaris
) and uses that as the seed.
So if the small token size is okay(in case of Random), you can continue using your code without any changes, since you are using SecureRandom to generate the seed. But if you want larger tokens(which cannot be subject to brute force attacks
) go with SecureRandom -
In case of random just 2^48
attempts are required, with todays advanced cpu's it is possible to break it in practical time. But for securerandom 2^128
attempts will be required, which will take years and years to break even with today's advanced machines.
See this link for more details.
EDIT
After reading the links provided by @emboss, it is clear that the seed, however random it maybe,
should not be used with java.util.Random. It is very easy to calculate the seed by observing the output.
Go for SecureRandom - Use Native PRNG (as given in the link above) because it takes random values from the /dev/random
file for each call to nextBytes()
. This way an attacker observing the output will not be able to make out anything unless he is controlling the contents of the /dev/random
file(which is very unlikely)
The sha1 prng algorithm calculates the seed only once and if your VM is running for months using the same seed, it might be cracked by an attacker who is passively observing the output.
NOTE - If you are calling the nextBytes()
faster than your os is able to write random bytes(entropy) into the /dev/random
, you might land into trouble when using NATIVE PRNG. In that case use a SHA1 PRNG instance of SecureRandom and every few minutes(or some interval), seed this instance with the value from nextBytes()
of a NATIVE PRNG instance of SecureRandom. Running these two parallely will ensure that you are seeding regularly with true random values, while also not exhausting the entropy obtained by the Operating System.
If you run twice java.util.Random.nextLong()
with the same seed, it will produce the same number. For security reasons you want to stick with java.security.SecureRandom
because it's a lot less predictable.
The 2 Classes are similar, I think you just need to change Random
to SecureRandom
with a refactoring tool and most of your existing code will work.
If changing your existing code is an affordable task, I suggest you use the SecureRandom class as suggested in Javadoc.
Even if you find the Random class implementation uses the SecureRandom class internally. you should not take it for granted that:
So it's a better choice to follow the documentation suggestion and go directly with SecureRandom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With