• 真伪随机数 ——Random和SecureRandom


    Random

    Random用来创建伪随机数。所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的。

    要生成一个随机数,可以使用nextInt()、nextLong()、nextFloat()、nextDouble():

    Random r = new Random();
    r.nextInt(); // 2071575453,每次都不一样
    r.nextInt(10); // 5,生成一个[0,10)之间的int
    r.nextLong(); // 8811649292570369305,每次都不一样
    r.nextFloat(); // 0.54335...生成一个[0,1)之间的float
    r.nextDouble(); // 0.3716...生成一个[0,1)之间的double
    

    有朋友会有疑问,每次运行程序,生成的随机数都是不同的,没看出伪随机数的特性来。

    这是因为我们创建Random实例时,如果不给定种子,就使用系统当前时间戳作为种子,因此每次运行时,种子不同,得到的伪随机数序列就不同。

    如果我们在创建Random实例时指定一个种子,就会得到完全确定的随机数序列:

    import java.util.Random;
    public class Main {
        public static void main(String[] args) {
            Random r = new Random(12345);
            for (int i = 0; i < 10; i++) {
                System.out.println(r.nextInt(100));
            }
            // 51, 80, 41, 28, 55...
        }
    }
    

    前面我们使用的Math.random()实际上内部调用了Random类,所以它也是伪随机数,只是我们无法指定种子。

    SecureRandom

    有伪随机数,就有真随机数。实际上真正的真随机数只能通过量子力学原理来获取,而我们想要的是一个不可预测的安全的随机数,SecureRandom就是用来创建安全的随机数的:

    SecureRandom sr = new SecureRandom();
    System.out.println(sr.nextInt(100));
    

    SecureRandom无法指定种子,它使用RNG(random number generator)算法。JDK的SecureRandom实际上有多种不同的底层实现,有的使用安全随机种子加上伪随机数算法来产生安全的随机数,有的使用真正的随机数生成器。实际使用的时候,可以优先获取高强度的安全随机数生成器,如果没有提供,再使用普通等级的安全随机数生成器:

    import java.util.Arrays;
    import java.security.SecureRandom;
    import java.security.NoSuchAlgorithmException;
    public class Main {
        public static void main(String[] args) {
            SecureRandom sr = null;
            try {
                sr = SecureRandom.getInstanceStrong(); // 获取高强度安全随机数生成器
            } catch (NoSuchAlgorithmException e) {
                sr = new SecureRandom(); // 获取普通的安全随机数生成器
            }
            byte[] buffer = new byte[16];
            sr.nextBytes(buffer); // 用安全随机数填充buffer
            System.out.println(Arrays.toString(buffer));
        }
    }
    

    SecureRandom的安全性是通过操作系统提供的安全的随机种子来生成随机数。这个种子是通过CPU的热噪声、读写磁盘的字节、网络流量等各种随机事件产生的“熵”。

    在密码学中,安全的随机数非常重要。如果使用不安全的伪随机数,所有加密体系都将被攻破。因此,时刻牢记必须使用SecureRandom来产生安全的随机数。

    需要使用安全随机数的时候,必须使用SecureRandom,绝不能使用Random!

  • 相关阅读:
    BZO4197 & 洛谷2150 & UOJ129:[NOI2015]寿司晚宴——题解
    BZOJ4198 & 洛谷2168 & UOJ130:[NOI2015]荷马史诗——题解
    BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)
    BZOJ4653 & 洛谷1712 & UOJ222:[NOI2016]区间——题解
    BZOJ4898 & BZOJ5367 & 洛谷3778:[APIO2017]商旅——题解
    BZOJ5340 & 洛谷4564 & LOJ2552:[CTSC2018]假面——题解
    举例分析 Makefile 中的 patsubst、wildcard、notdir 函数
    伪指令 ENTRY 与 END
    伪指令 ADR 与 LDR 的区别
    μC/OS-II 信号量集
  • 原文地址:https://www.cnblogs.com/yonyong/p/11341330.html
Copyright © 2020-2023  润新知