ZetCode

Java SecureRandom

Last modified: July 16, 2026

This Java SecureRandom tutorial shows how to generate cryptographically secure random numbers in Java using the SecureRandom class. We cover generating random integers, doubles, byte arrays, seeds, and cryptographic keys.

SecureRandom

SecureRandom is a Java class that generates cryptographically strong random numbers. Unlike java.util.Random, which uses a linear congruential formula, SecureRandom employs a cryptographically strong pseudo-random number generator (CSPRNG). It gathers entropy from the underlying operating system (e.g., /dev/random and /dev/urandom on Unix-like systems) to produce unpredictable outputs suitable for security-sensitive applications.

The key methods of SecureRandom are:

Method Description
nextInt() Returns a uniformly distributed integer.
nextInt(int bound) Returns an integer between 0 (inclusive) and bound (exclusive).
nextDouble() Returns a double between 0.0 (inclusive) and 1.0 (exclusive).
nextBytes(byte[]) Fills a byte array with random bytes.
getInstance(String algorithm) Creates a SecureRandom instance with a specific algorithm.
setSeed(byte[]) Seeds (or reseeds) the random generator.
generateSeed(int) Returns a seed byte array from system entropy.

Generating random integers and doubles

The following example shows basic SecureRandom usage to generate random integers, doubles, and byte arrays.

Main.java
import java.security.SecureRandom;

void main() {

    SecureRandom sr = new SecureRandom();

    int ri = sr.nextInt();
    System.out.println("Random int: " + ri);

    int ri2 = sr.nextInt(100);
    System.out.println("Random int (0-99): " + ri2);

    double rd = sr.nextDouble();
    System.out.println("Random double: " + rd);

    byte[] data = new byte[6];
    sr.nextBytes(data);
    System.out.print("Random bytes: ");

    for (byte b : data) {
        System.out.printf("%02x ", b);
    }

    System.out.println();
}

The example creates a SecureRandom instance and calls its basic methods. The nextInt method returns a random integer; the nextInt(100) returns a value between 0 and 99. The nextDouble returns a double between 0.0 and 1.0, and nextBytes fills a byte array with random values.

Generating numbers in a range

The following program generates random integers and doubles within a specific range.

Main.java
import java.security.SecureRandom;

void main() {

    SecureRandom sr = new SecureRandom();

    int min = 10;
    int max = 20;

    int ri = sr.nextInt(max - min + 1) + min;
    System.out.printf("Random int (%d-%d): %d%n", min, max, ri);

    double rd = min + (max - min) * sr.nextDouble();
    System.out.printf("Random double (%d-%d): %.2f%n", min, max, rd);
}
int ri = sr.nextInt(max - min + 1) + min;

An integer in a closed interval [min, max] is produced by calculating the range size (max - min + 1), generating a value from 0 to that size, and shifting by min.

double rd = min + (max - min) * sr.nextDouble();

A double in a half-open interval [min, max) is created by scaling nextDouble by the range width and adding the minimum.

Generating secure random strings

The following example creates secure random strings from a character alphabet. Secure random strings are used for session identifiers, API tokens, and temporary passwords.

Main.java
import java.security.SecureRandom;

void main() {

    var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    var sr = new SecureRandom();

    var token1 = new StringBuilder(8);

    for (int i = 0; i < 8; i++) {
        token1.append(alphabet.charAt(sr.nextInt(alphabet.length())));
    }

    System.out.println("Token (8 chars): " + token1);

    var token2 = new StringBuilder(16);

    for (int i = 0; i < 16; i++) {
        token2.append(alphabet.charAt(sr.nextInt(alphabet.length())));
    }

    System.out.println("Token (16 chars): " + token2);
}
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

We define a character set containing upper-case letters, lower-case letters, and digits—62 characters in total.

token1.append(alphabet.charAt(sr.nextInt(alphabet.length())));

Inside the loop, we use sr.nextInt(alphabet.length()) to pick a random index into the alphabet and append the character at that index to a StringBuilder.

$ java Main.java
Token (8 chars): a3Fg7K2x
Token (16 chars): B9mQ4rX8tL2pZw5N

Using specific algorithms

SecureRandom supports different algorithms via the getInstance factory method. Common algorithms include SHA1PRNG (a Java-built-in PRNG using SHA-1) and NativePRNG (which reads from the OS entropy source).

Main.java
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;

void main() {

    try {

        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
        System.out.println("SHA1PRNG int: " + sr1.nextInt());

        SecureRandom sr2 = SecureRandom.getInstance("NativePRNG");
        System.out.println("NativePRNG int: " + sr2.nextInt());

    } catch (NoSuchAlgorithmException e) {
        System.err.println("Algorithm not available: " + e.getMessage());
    }
}

The example requests specific algorithms via SecureRandom.getInstance. Not all algorithms are available on every platform; a NoSuchAlgorithmException is thrown if the requested algorithm is not present.

Seeding SecureRandom

By default, SecureRandom self-seeds from system entropy. However, we can seed it manually with setSeed to produce reproducible sequences, which is useful for testing.

Main.java
import java.security.SecureRandom;

void main() {

    byte[] seed = { 1, 2, 3, 4 };

    SecureRandom sr1 = new SecureRandom();
    sr1.setSeed(seed);

    SecureRandom sr2 = new SecureRandom();
    sr2.setSeed(seed);

    System.out.println("sr1: " + sr1.nextInt());
    System.out.println("sr2: " + sr2.nextInt());
}

Both instances are seeded with the same four bytes, so they produce identical output sequences. In production, manual seeding is discouraged because it reduces unpredictability.

$ java Main.java
sr1: -1157522390
sr2: -1157522390

Generating seeds

The generateSeed method returns a seed byte array obtained directly from system entropy, without affecting the internal state of the SecureRandom instance.

Main.java
import java.security.SecureRandom;

void main() {

    SecureRandom sr = new SecureRandom();

    byte[] seed = sr.generateSeed(16);

    System.out.print("Generated seed: ");
    
    for (byte b : seed) {
        System.out.printf("%02x", b);
    }

    System.out.println();
}

The generateSeed method is useful when we need entropy for initializing other cryptographic primitives without altering the state of our main SecureRandom instance.

$ java Main.java
Generated seed: 2f7a1b4c8e3d9f05a6c2b8e4d1f7093a

Generating cryptographic keys

A common use of SecureRandom is generating symmetric keys for encryption algorithms such as AES. The following example creates 128-bit and 256-bit keys.

Main.java
import java.security.SecureRandom;
import java.util.Base64;

void main() {

    SecureRandom sr = new SecureRandom();

    // 256-bit key
    byte[] key256 = new byte[32];
    sr.nextBytes(key256);
    System.out.println("256-bit key (Base64): "
            + Base64.getEncoder().encodeToString(key256));

    // 128-bit key
    byte[] key128 = new byte[16];
    sr.nextBytes(key128);
    System.out.print("128-bit key (hex): ");
    for (byte b : key128) {
        System.out.printf("%02x", b);
    }
    System.out.println();
}

The example fills byte arrays of 32 and 16 bytes with cryptographically strong random values, suitable for AES-256 and AES-128 keys respectively. The keys are displayed in Base64 and hexadecimal formats.

Performance considerations

SecureRandom is significantly slower than Random because it gathers entropy and uses cryptographic operations. The following program compares the throughput of both classes.

Main.java
import java.security.SecureRandom;
import java.util.Random;

void main() {

    int count = 1_000_000;
    long start = System.currentTimeMillis();
    Random r = new Random();

    for (int i = 0; i < count; i++) {
        r.nextInt();
    }

    long dur1 = System.currentTimeMillis() - start;
    System.out.println("Random: " + dur1 + " ms");

    start = System.currentTimeMillis();
    SecureRandom sr = new SecureRandom();

    for (int i = 0; i < count; i++) {
        sr.nextInt();
    }

    long dur2 = System.currentTimeMillis() - start;
    System.out.println("SecureRandom: " + dur2 + " ms");
}

The program generates one million random integers with each class and measures the elapsed time.

$ java Main.java
Random: 18 ms
SecureRandom: 112 ms

SecureRandom should only be used when cryptographic security is required. For non-sensitive tasks (simulations, games, shuffling), prefer Random or ThreadLocalRandom.

Source

Java SecureRandom documentation

This tutorial covered the Java SecureRandom class. We have shown how to generate random integers, doubles, byte arrays, tokens, seeds, and cryptographic keys.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Java tutorials.