Java中的随机数类:Random和SecureRandom

2023年2月27日15:15:37Java中的随机数类:Random和SecureRandom已关闭评论

Java提供了两个类来为用户提供随机数功能,分别是类Random和类SecureRandom。SecureRandom是从Random派生而来的,且专门用于要求高的密码学场合。类Random一般用于随机性要求不高的场合,但是速度快。

类Random用来创建伪随机数,如果给定一个初始的种子,产生的随机数序列是完全一样的;如果不给定种子,就使用系统当前时间戳作为种子,那么每次运行时,种子不同,得到的伪随机数序列就不同。要生成一个随机数,可以使用其成员方法nextInt()、nextLong()、nextFloat()、nextDouble()等,比如下列代码生成的伪随机数就不同:

Java中的随机数类:Random和SecureRandom

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

Java中的随机数类:Random和SecureRandom

顺便提一句,有时会看到Java代码调用Math.random()来产生随机数。Math.random()实际上在内部调用了Random类,所以它也是伪随机数,只是我们无法指定种子。

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

类SecureRandom本身并不是伪随机算法的实现,而是使用了其他类提供的算法来获取伪随机数。不指定算法的时候,在不同的操作平台会获取到不同的算法,Windows默认是SHA1PRNG,Linux是NativePRNG。Linux下的NativePRNG如果调用generateSeed()方法,就会读取Linux系统的/dev/random文件(这个文件在JAVA_HOME/jre/lib/securiy/java.security里面有默认定义)。/dev/random文件是动态生成的,如果没有数据,就会阻塞。如果使用SecureRandom.getInstanceStrong()初始化SecureRandom对象,就会使用NativePRNGBlocking算法。

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

Java中的随机数类:Random和SecureRandom

如果没有获取高强度安全随机数生成器,就会抛出异常NoSuchAlgorithmException,从而获取普通的安全随机数生成器。

类SecureRandom提供了能满足加密要求的强随机数生成器。随机数在密码学中有着地基的地位。至关重要的密钥首先必须是一个安全的随机数。密码学意义上的安全随机数要求必须保证其不可预测性,实际上,密码学中有15项随机数检测规则,限于篇幅,这里不展开了。怎么得到安全的随机数?通常可以通过硬件随机数芯片来获得,也可以通过非物理的随机数产生器来获得。目前,三大非物理的随机数产生器有Linux操作系统的/dev/random设备接口、Windows操作系统的CryptGenRandom接口、JDK的java.security.SecureRandom类。

总而言之,类SecureRandom的安全性是通过操作系统提供的安全随机种子来生成随机数的。这个种子是通过CPU的热噪声、读写磁盘的字节、网络流量等各种随机事件产生的“熵”。在密码学中,安全的随机数非常重要。如果使用不安全的伪随机数,那么所有加密体系都将被攻破。因此,时刻牢记必须使用SecureRandom来产生安全的随机数。需要使用安全随机数的时候,必须使用SecureRandom,绝不能使用Random。

  • A+
所属分类:JAVA
  • 版权声明:本篇文章(包括图片)来自网络,由程序自动采集,著作权(版权)归原作者所有,如有侵权联系我们删除,联系方式(QQ:452038415)。