ZetCode

Java SecureRandom 类

上次修改:2025 年 4 月 26 日

SecureRandom 类是 Java 安全包的一部分,用于生成密码学上安全的随机数。它提供了生成安全的随机整数、双精度浮点数和字节数组的方法。

安全随机数生成对于密码学、安全令牌和敏感应用程序至关重要。SecureRandom 使用强大的算法来确保不可预测和高质量的随机性。

SecureRandom 类概述

SecureRandom 扩展了 Random 类,但专为安全关键任务而设计。 它利用系统熵或安全算法来生成适合密码学使用的随机值。

关键方法包括 nextIntnextDoublenextBytes。虽然比 Random 慢,但它提供卓越的随机性,这对于安全应用程序至关重要。

基本安全随机数生成

此示例演示了 SecureRandom 的基本用法,用于为安全应用程序生成随机整数、双精度浮点数和字节数组。

BasicSecureRandom.java
package com.zetcode;

import java.security.SecureRandom;

public class BasicSecureRandom {

    public static void main(String[] args) {
        
        SecureRandom secureRandom = new SecureRandom();
        
        // Generate random integer
        int randInt = secureRandom.nextInt();
        System.out.println("Secure random integer: " + randInt);
        
        // Generate random integer between 0 and 100 (exclusive)
        int randIntRange = secureRandom.nextInt(100);
        System.out.println("Secure random integer (0-99): " + randIntRange);
        
        // Generate random double
        double randDouble = secureRandom.nextDouble();
        System.out.println("Secure random double: " + randDouble);
        
        // Generate random byte array
        byte[] bytes = new byte[8];
        secureRandom.nextBytes(bytes);
        System.out.print("Secure random bytes: ");
        for (byte b : bytes) {
            System.out.printf("%02x", b);
        }
        System.out.println();
    }
}

此程序创建一个 SecureRandom 实例来生成各种随机值。 字节数组以十六进制显示,以提高可读性。

每次执行都会产生不可预测的结果,利用系统熵来实现密码学强度,使其成为安全敏感任务的理想选择。

在范围内生成安全随机数

此示例展示了如何使用 SecureRandom 在特定范围内生成安全随机数,这对于安全令牌生成非常有用。

SecureRandomRange.java
package com.zetcode;

import java.security.SecureRandom;

public class SecureRandomRange {

    public static void main(String[] args) {
        
        SecureRandom secureRandom = new SecureRandom();
        int min = 10;
        int max = 20;
        
        // Generate secure random integer in range [min, max]
        int randInt = secureRandom.nextInt(max - min + 1) + min;
        System.out.println("Secure random int (" + min + "-" + max + "): " + randInt);
        
        // Generate secure random double in range [min, max)
        double randDouble = min + (max - min) * secureRandom.nextDouble();
        System.out.println("Secure random double (" + min + "-" + max + "): " + randDouble);
    }
}

该程序使用 nextIntnextDouble 生成自定义范围内的数字,确保输出值的密码学安全性。

这种方法适用于安全 PIN 生成或随机密码参数等应用,其中不可预测性至关重要。

生成安全随机字符串

此示例说明了如何使用 SecureRandom 创建随机字符串,非常适合生成安全密码或会话标识符。

SecureRandomString.java
package com.zetcode;

import java.security.SecureRandom;

public class SecureRandomString {

    private static final String CHARACTERS = 
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    public static String generateSecureString(SecureRandom random, int length) {
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(CHARACTERS.length());
            sb.append(CHARACTERS.charAt(index));
        }
        
        return sb.toString();
    }

    public static void main(String[] args) {
        SecureRandom secureRandom = new SecureRandom();
        
        System.out.println("Secure random string (8 chars): " + 
            generateSecureString(secureRandom, 8));
        System.out.println("Secure random string (16 chars): " + 
            generateSecureString(secureRandom, 16));
    }
}

我们定义了一个字符集,并使用 SecureRandom 选择随机字符,构建指定长度的安全字符串,用于敏感用例。

此方法非常适合创建安全令牌或密码,确保高随机性并抵抗安全关键应用程序中的预测。

使用特定算法

此示例演示了如何使用特定的密码学算法配置 SecureRandom,以增强随机数生成的安全性。

SecureRandomAlgorithm.java
package com.zetcode;

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

public class SecureRandomAlgorithm {

    public static void main(String[] args) {
        
        try {
            // Use SHA1PRNG algorithm
            SecureRandom sha1prng = SecureRandom.getInstance("SHA1PRNG");
            System.out.println("SHA1PRNG random int: " + sha1prng.nextInt());
            
            // Use NativePRNG algorithm
            SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG");
            System.out.println("NativePRNG random int: " + nativePrng.nextInt());
            
            // Generate secure bytes with NativePRNG
            byte[] bytes = new byte[8];
            nativePrng.nextBytes(bytes);
            System.out.print("NativePRNG bytes: ");
            for (byte b : bytes) {
                System.out.printf("%02x", b);
            }
            System.out.println();
            
        } catch (NoSuchAlgorithmException e) {
            System.err.println("Algorithm not available: " + e.getMessage());
        }
    }
}

我们使用诸如 SHA1PRNG 或 NativePRNG 之类的特定算法实例化 SecureRandom,从而可以为特定的安全需求定制随机性。

算法的选择取决于应用程序的要求。 此示例展示了如何处理不可用算法的潜在异常。

播种 SecureRandom

此示例展示了如何手动播种 SecureRandom,这对于测试中的可重现结果很有用,但在生产中通常为了安全而避免使用。

SecureRandomSeed.java
package com.zetcode;

import java.security.SecureRandom;

public class SecureRandomSeed {

    public static void main(String[] args) {
        
        SecureRandom secureRandom1 = new SecureRandom();
        SecureRandom secureRandom2 = new SecureRandom();
        
        // Set the same seed for both instances
        byte[] seed = new byte[]{1, 2, 3, 4};
        secureRandom1.setSeed(seed);
        secureRandom2.setSeed(seed);
        
        // Generate random integers
        System.out.println("First SecureRandom int: " + secureRandom1.nextInt());
        System.out.println("Second SecureRandom int: " + secureRandom2.nextInt());
    }
}

我们为两个 SecureRandom 实例设置相同的种子,产生一致的结果。 在实践中,手动播种很少见,以保持不可预测性。

这对于调试或测试密码系统很有用,但在生产中应避免使用,以确保最大的随机性和安全性。

生成安全随机密钥

此示例演示了如何使用 SecureRandom 生成密码学密钥,这是安全通信协议中的常见要求。

SecureRandomKey.java
package com.zetcode;

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

public class SecureRandomKey {

    public static void main(String[] args) {
        
        SecureRandom secureRandom = new SecureRandom();
        
        // Generate a 256-bit (32-byte) key
        byte[] key = new byte[32];
        secureRandom.nextBytes(key);
        
        // Encode to Base64 for readable output
        String base64Key = Base64.getEncoder().encodeToString(key);
        System.out.println("Secure 256-bit key (Base64): " + base64Key);
        
        // Generate a 128-bit (16-byte) key
        byte[] shortKey = new byte[16];
        secureRandom.nextBytes(shortKey);
        System.out.print("Secure 128-bit key (hex): ");
        for (byte b : shortKey) {
            System.out.printf("%02x", b);
        }
        System.out.println();
    }
}

该程序生成适用于密码学密钥的安全字节数组,输出采用 Base64 和十六进制格式,以提高清晰度和可用性。

此类密钥对于 AES 等加密算法至关重要,可确保安全敏感应用程序中的安全数据传输或存储。

性能注意事项

此示例比较了 SecureRandomRandom 的性能,突出了随机数生成中安全性和速度之间的权衡。

SecureRandomPerformance.java
package com.zetcode;

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

public class SecureRandomPerformance {

    static final int COUNT = 1000000;

    public static void main(String[] args) {
        
        // Test Random
        long start = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < COUNT; i++) {
            random.nextInt();
        }
        long duration = System.currentTimeMillis() - start;
        System.out.println("Random time: " + duration + "ms");
        
        // Test SecureRandom
        start = System.currentTimeMillis();
        SecureRandom secureRandom = new SecureRandom();
        for (int i = 0; i < COUNT; i++) {
            secureRandom.nextInt();
        }
        duration = System.currentTimeMillis() - start;
        System.out.println("SecureRandom time: " + duration + "ms");
    }
}

我们测量了使用两个类生成随机整数所花费的时间。 由于其密码学强度,SecureRandom 速度较慢,但对于安全性而言是必要的。

仅当需要密码学安全性时才使用 SecureRandom,因为对于非敏感任务,RandomThreadLocalRandom 速度更快。

来源

Java SecureRandom 文档

本教程全面探讨了 Java SecureRandom 类,涵盖了基本用法、范围生成、安全字符串和密码学密钥。 这对于安全应用程序至关重要。

作者

我是 Jan Bodnar,一位充满激情的程序员,拥有丰富的经验。 自 2007 年以来,我撰写了 1,400 多篇文章和 8 本电子书。 拥有超过 8 年的教学经验,我致力于分享知识并帮助他人学习编程概念。

列出所有Java教程