How should you use SecureRandom in practice, and what are the common pitfalls (blocking, seeding, getInstanceStrong)?
answer
- reuse one instance, it's thread-safe
- nextBytes(buf) then Base64/hex encode
- new SecureRandom() = fast/non-blocking default
- getInstanceStrong() for keys, may block, off hot path
- NEVER fixed-seed it; 16-32 bytes for tokens
basics
~20 sCreate one SecureRandom and reuse it to generate bytes for tokens or keys. Don't give it a fixed seed (that makes it predictable). On some setups it can pause briefly the first time while it gathers randomness.
solid answer
~40 sConstruct a SecureRandom once and reuse it (it's thread-safe); generating fresh bytes is the normal pattern: byte[] buf = new byte[32]; random.nextBytes(buf). For most needs — session IDs, CSRF/reset tokens, salts — the default new SecureRandom() is correct and non-blocking on modern platforms. For long-lived cryptographic keys you may prefer SecureRandom.getInstanceStrong(), which selects the strongest configured algorithm but can block while gathering entropy, so don't call it on a hot/request path. The cardinal sin is calling setSeed() with a fixed value to make output 'reproducible' — that destroys unpredictability. Also don't roll your own from System.currentTimeMillis(). Be aware of historical platform quirks (e.g. SHA1PRNG behavior, the old Android SecureRandom seeding bug) but on current JDKs the defaults are sound. Size tokens generously (e.g. 16-32 random bytes) so they're infeasible to guess.
go deeper
Knows SecureRandom is the 'safe' generator and that you shouldn't seed it with a fixed value.
Uses nextBytes + encoding to make tokens, reuses one instance, and knows not to fix the seed.
Explains entropy/blocking, when to use getInstanceStrong vs new SecureRandom, token sizing, and avoids fixed seeding and hot-path blocking.
Sets crypto-randomness standards (algorithms, sizing, provider choice), reasons about startup-entropy/FIPS concerns, and reviews code for weak-source and seeding mistakes.
### What SecureRandom is `SecureRandom` is Java's **cryptographically secure** random source (a CSPRNG). It extends `java.util.Random` but plugs in an engine from the **JCA (Java Cryptography Architecture)** that draws on operating-system entropy (e.g. Linux `/dev/random`/`/dev/urandom`, Windows crypto APIs) and uses algorithms designed so that seeing outputs never helps you predict the next one. Use it for anything an attacker benefits from guessing: tokens, session IDs, salts, nonces, IVs, key material. ### Entropy and blocking 'Entropy' is real-world unpredictability the OS collects (timing of interrupts, hardware RNGs, etc.). A CSPRNG is *seeded* from entropy and then stretches it into a long unpredictable stream. - On a freshly booted machine with little entropy, requesting strong randomness can **block** until enough is gathered. This is the classic 'my app hangs on startup' symptom. - Modern Linux `/dev/urandom` (and the JDK defaults) are non-blocking once initialized, which is why **`new SecureRandom()` is usually fine and fast**. - **`SecureRandom.getInstanceStrong()`** asks for the platform's strongest configured source. It is appropriate for generating **long-lived keys**, but it *may block*, so never call it on a per-request hot path — create it once, off the critical path. ### Correct usage patterns ```java // reuse a single instance; it is thread-safe private static final SecureRandom RNG = new SecureRandom(); // generate a 256-bit token byte[] tokenBytes = new byte[32]; RNG.nextBytes(tokenBytes); String token = Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes); ``` - **Reuse one instance.** `SecureRandom` is thread-safe; you don't need a new one per call (and constructing repeatedly wastes effort). - **Generate bytes, then encode** (Base64/hex) for tokens — don't try to map ints to characters by hand and introduce bias. - **Size for security:** 16 bytes (128 bits) is a common floor; 32 bytes (256 bits) is comfortably safe. ### The pitfalls 1. **Fixed seeding for 'reproducibility'.** Calling `setSeed(42)` (or constructing from a fixed seed) to get deterministic output **defeats the entire purpose** — output becomes predictable. If you genuinely need deterministic test data, use `java.util.Random`, not `SecureRandom`. (Note: `SecureRandom` *adds* a fixed seed to existing entropy rather than replacing it in some providers, but relying on that is still wrong.) 2. **Calling `getInstanceStrong()` on a hot path** and getting intermittent blocking/latency spikes. 3. **Rolling your own** from `System.currentTimeMillis()`, `UUID.randomUUID()` for *secrets* (random UUIDs are 122 bits but intended as identifiers, not always vetted as secret tokens — prefer SecureRandom bytes), or hashing weak inputs. 4. **Historical provider quirks:** `SHA1PRNG` behaves differently across providers; the old **Android 2013 SecureRandom seeding bug** weakened keys. On current JDKs the defaults are sound, but legacy code may explicitly request weak providers. ### Choosing the constructor - Tokens/salts/session IDs, high volume -> `new SecureRandom()` (fast, non-blocking on modern platforms). - Long-lived asymmetric/symmetric **keys** -> `SecureRandom.getInstanceStrong()`, created once off the request path. ### Modern note Since Java 17 `SecureRandom` participates in the `RandomGenerator` API, but you continue to select it explicitly when you need cryptographic strength — the algorithm choice is the whole point, so you would not pick it via a generic factory by accident.
- Why might an app hang on startup when generating cryptographic randomness?On a low-entropy machine, blocking strong-randomness sources (or getInstanceStrong) wait until the OS gathers enough entropy. Use the non-blocking default for tokens and create strong instances once, off the critical path.
- Is UUID.randomUUID() a safe security token?It uses a random source and gives ~122 random bits, which is often adequate, but it's intended as an identifier, not a vetted secret-token API. For secrets prefer SecureRandom.nextBytes with explicit sizing/encoding.
saying these in an interview costs you the question
- setSeed(fixedValue) to make SecureRandom 'reproducible'
- Calling getInstanceStrong() per request and causing latency/hangs
- Building secrets from System.currentTimeMillis() or weak inputs
- Allocating a new SecureRandom for every token (wasteful, not safer)
- Hand-mapping random ints to chars and introducing modulo bias