Back to Blog
Java

Java Secure Random: Using SecureRandom Instead of Random

This article explains java secure random generation with SecureRandom: seeding, thread safety, performance, and when to use it instead of Random.

SecureRandomJava SecurityRandom Number GenerationCryptographyThread Safety
SecureRandom class generating random bytes with a shield representing security

Generating a java secure random value is not the same as calling new Random().nextInt(). The standard java.util.Random uses a linear congruential generator that is fast but predictable once enough output is observed. For security-sensitive values such as session identifiers, password reset tokens, salts, and encryption keys, use java.security.SecureRandom.

Why Random Is Not a Secure Choice

java.util.Random is designed for simulations, shuffling, and other non-security use cases. Its algorithm has a finite state, and if an attacker can observe a sequence of outputs, they can often recover the internal state and predict future values. That makes it unsuitable for anything an attacker might try to guess.

Math.random() is not better. It delegates to a shared Random instance, so it has the same predictability problem and adds contention because every call goes through the same object.

What SecureRandom Provides

SecureRandom is a cryptographically strong random number generator (CSPRNG). It draws entropy from the operating system's secure sources, such as /dev/urandom on Linux or the CryptGenRandom API on Windows. The exact algorithm depends on the JVM and provider configuration, but the contract is that the output is suitable for cryptographic use.

You do not need to seed SecureRandom manually. The default constructor performs self-seeding from the platform entropy source. That is one of the main differences from Random, where you often pass a seed to reproduce a sequence.

Creating a SecureRandom Instance

The simplest way to get an instance is:

SecureRandom secureRandom = new SecureRandom();

This uses the default SecureRandom algorithm configured for your JVM. It is the right choice for most applications.

If you need a stronger instance, you can call:

SecureRandom strongRandom = SecureRandom.getInstanceStrong();

This returns an instance that uses a stronger algorithm if one is configured. On some platforms, that call can block until enough entropy is available, so it is not always appropriate during application startup.

Seeding and Self-Seeding Behavior

When you create a SecureRandom with new SecureRandom(), it seeds itself from the operating system. You rarely need to call setSeed() yourself. If you do, the provided seed supplements the existing seed rather than replacing it. The documentation guarantees that repeated calls never reduce randomness.

SecureRandom secureRandom = new SecureRandom(); byte[] extraEntropy = getEntropyFromSomewhere(); secureRandom.setSeed(extraEntropy);

This can be useful if you have an additional entropy source, but it is not a substitute for letting SecureRandom do its own seeding.

Thread Safety and Sharing Instances

SecureRandom instances are safe for use by multiple threads. The class synchronizes access to its internal state, so you can share one instance across your application without corrupting the generator.

Sharing does have a cost. When many threads call nextBytes() at the same time, they serialize on the same lock. If random generation is a hot path, consider using a ThreadLocal<SecureRandom> to reduce contention.

private static final ThreadLocal<SecureRandom> RANDOM = ThreadLocal.withInitial(SecureRandom::new); byte[] bytes = new byte[16]; RANDOM.get().nextBytes(bytes);

Each thread gets its own instance, so the lock is no longer shared. This is a common pattern for high-throughput token generation.

Performance and Entropy Considerations

SecureRandom is slower than Random because it performs cryptographic operations and may periodically reseed from the operating system. The exact overhead depends on the algorithm and platform, but you should not use SecureRandom for non-security work such as procedural generation or Monte Carlo simulations.

Entropy gathering can also block. The default new SecureRandom() usually reads from a non-blocking entropy source, but getInstanceStrong() may wait for the system to accumulate enough entropy. On a headless server, this can cause a noticeable pause at startup. If you see long delays, check the JVM's securerandom.source configuration and the platform's entropy availability.

Choosing Between Random and SecureRandom

AspectRandomSecureRandom
AlgorithmLinear congruentialCSPRNG
PredictabilityPredictable after enough outputNot feasible to predict
SeedingManual, reproducibleAutomatic from OS entropy
Thread safetySafe but shared by Math.randomSafe, but lock contention possible
Use casesSimulations, shuffling, testingTokens, keys, salts, IVs

Use Random when the output does not need to be unpredictable. Use SecureRandom whenever an attacker could benefit from guessing the value. There is no middle ground for security-sensitive data.

Generating a Secure Token with SecureRandom

A common task is generating a random token for password resets or API keys. The following example creates a 32-byte random value and encodes it as a URL-safe Base64 string:

SecureRandom secureRandom = new SecureRandom(); byte[] tokenBytes = new byte[32]; secureRandom.nextBytes(tokenBytes); String token = Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);

The token contains 256 bits of entropy, which is sufficient for most security contexts. Do not reduce the size below 16 bytes unless you have a specific reason, because shorter tokens are easier to brute force.

Handling Blocking and Entropy in Production

In production, the most common issue with SecureRandom is not the generator itself but the environment. If the operating system cannot provide enough entropy, calls that need strong randomness may block. This can happen on virtual machines or containers that lack a hardware random number generator.

To reduce the risk, prefer new SecureRandom() over getInstanceStrong() unless you have a strict requirement for a stronger algorithm. You can also configure the JVM to use a specific entropy source by setting the securerandom.source property in java.security. On Linux, setting it to file:/dev/urandom avoids blocking, but you should understand the security tradeoff before doing so.

Monitor startup time and any random-generation calls in your application. If you see stalls, check whether the platform entropy source is healthy. In most cases, the default SecureRandom is the right balance of security and availability.

java secure random: Practical Usage and Code Examples | RYUSLOG DEV