According to the documentation, the different algorithms used by SecureRandom are, in order of preference:
- On most *NIX systems (including macOS)
- PKCS11 (only on Solaris)
- NativePRNG
- DRBG
- SHA1PRNG
- NativePRNGBlocking
- NativePRNGNonBlocking
- On Windows systems
- DRBG
- SHA1PRNG
- Windows-PRNG
Since you asked about Linux, I will ignore the Windows implementation, as well as PKCS11 which is only really available on Solaris, unless you installed it yourself — and if you did, you probably wouldn't be asking this question.
According to that same documentation, what these algorithms use are
NativePRNG
generateSeed()
uses /dev/random
nextBytes()
uses /dev/urandom
NativePRNGBlocking
generateSeed()
and nextBytes()
use /dev/random
NativePRNGNonBlocking
generateSeed()
and nextBytes()
use /dev/urandom
DRBG
Supported mechanisms and algorithms:
- Hash_DRBG and HMAC_DRBG with SHA-224, SHA-512/224, SHA-256, SHA-512/256, SHA-384, and SHA-512.
- CTR_DRBG with AES-128, AES-192, and AES-256.
SHA1PRNG
Initial seeding is currently done via a combination of system attributes and the java.security entropy gathering device.
That means if you use SecureRandom random = new SecureRandom()
, it goes down that list until it finds one that works, which will typically be NativePRNG. And that means that it seeds itself from /dev/random
(or uses that if you explicitly generate a seed), then uses /dev/urandom
for getting the next bytes, ints, double, booleans, what-have-yous.
Since /dev/random
is blocking (it blocks until it has enough entropy in the entropy pool), that may impede performance.
One solution to that is using something like haveged to generate enough entropy, another solution is using /dev/urandom
instead. While you could set that for the entire jvm, a better solution is doing it for this specific instance of SecureRandom
, by using SecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
. Note that that method can throw a NoSuchAlgorithmException if NativePRNGNonBlocking is unavailable, so be prepared to fall back to the default.
SecureRandom random;
try {
random = SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException nsae) {
random = new SecureRandom();
}
Also note that on other *nix systems, /dev/urandom
may behave differently.
Is /dev/urandom
random enough?
Conventional wisdom has it that only /dev/random
is random enough. However, some voices differ. In "The Right Way to Use SecureRandom" and "Myths about /dev/urandom", it is argued that /dev/urandom/
is just as good.
The users over on the Information Security stack agree with that. Basically, if you have to ask, /dev/urandom
is fine for your purpose.