概览
伪随机数生成器 (PRNG) 是一种根据称为种子的起始值生成可预测的数字序列的算法。由 PRNG 生成的数字序列在属性上与真正的随机数序列大致相同,但前者创建速度更快,计算开销也更低。
也就是说,对于模拟真正的随机数序列的熵分配,在均匀性方面,PRNG 比弱 RNG(例如 java.math.Random
)更有保证。真正随机数的生成需要专门的设备,通常不在正常开发的范围之内。本文并不涵盖真正随机数的生成,仅重点介绍 PRNG,因为 PRNG 是当下使用的标准方法。
如果开发者使用常规 PRNG 进行加密,而不采用确保加密安全的 PRNG (CSPRNG),就会出现弱 PRNG 漏洞。CSPRNG 有更严格的要求,当种子未知时,它们只能让攻击者在区分输出序列与实际随机序列方面占据微乎其微的优势。
当系统使用可预测的种子(例如开发者硬编码的种子)来初始化 PRNG 或 CSPRNG 时,攻击者或许还可以猜测生成的种子序列,因为攻击者可以猜测出这些种子,从而预测 PRNG 生成的输出。
1、java.util.Random()
伪随机,如果不传入种子,以当前系统时间为种子,通过一系列计算得出随机值,种子相同的情况下,每次调用得到的随机值是固定的
2、Math.random()
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
Math内部也是通过java.util.Random()实现的
3、java.security.SecureRandom()
new SecureRandom();
SecureRandom rand = SecureRandom.getInstance("");
SecureRandom rand = SecureRandom.getInstanceStrong(); (推荐使用)
可以使用以上三种方式生成对象,推荐使用new SecureRandom(),使用系统默认的算法并由系统生成种子
SecureRandom继承于Random类,其具体的实现类为SecureRandomSpi,与平台相关,以JDK版本jdk-8u251-linux-x64为例,在Linux系统下,其默认的实现类为NativePRNG,随机源为/dev/random以及/dev/urandom
/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,使用这两个设备可以为应用提供不为空的随机字节流,两者的区别是/dev/random在系统噪声不足时,会产生阻塞,而/dev/urandom是/dev/random的一个副本,它会重复使用熵池中的数据以产生伪随机数据,因此不会有阻塞的问题
NativePRNG基于混合模式,为生成随机数与随机种子提供了不同的支持
常规
- 如果会有安全方面的影响,请使用 java.security.SecureRandom。
- 安全随机数推荐使用 SecureRandom.getInstanceStrong(“SHA1PRNG”);
- 避免用于安全/身份验证目的,适用于任何其他用途。请使用 java.util.Random
- 切勿使用 Math.random!
https://developer.android.com/privacy-and-security/risks/weak-prng?hl=zh-cn#java
https://www.cnblogs.com/yytxdy/p/12845248.html