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.