1. 简介
在本篇简明教程中,我们将深入了解 java.security.SecureRandom
类。这是一个用于生成密码学强度的随机数生成器(Cryptographically Strong Random Number Generator)的类。
2. 与 java.util.Random 的对比
标准 JDK 中的 java.util.Random
类通常使用的是 线性同余生成器(LCG)算法。这个算法虽然效率高,但并不适合用于安全场景,因为其生成的随机数序列是高度可预测的,攻击者可能利用这一特性入侵系统。
而 SecureRandom
使用的是密码学安全伪随机数生成器(Cryptographically Secure Pseudorandom Number Generator, CSPRNG)算法,生成的随机数具有更高的不可预测性,适合用于安全相关的场景,如生成密钥、令牌、盐值等。
下图展示了 LCG 与 CSPRNG 在数值分布上的差异:
3. 生成随机值
使用 SecureRandom
可以简单高效地生成各种基本类型的随机值,包括 int
、long
、float
、double
和 boolean
:
int randomInt = secureRandom.nextInt();
long randomLong = secureRandom.nextLong();
float randomFloat = secureRandom.nextFloat();
double randomDouble = secureRandom.nextDouble();
boolean randomBoolean = secureRandom.nextBoolean();
如果想生成指定范围内的整数,可以传入一个上限值:
int randomInt = secureRandom.nextInt(upperBound);
此外,还可以生成随机值的流:
IntStream randomIntStream = secureRandom.ints();
LongStream randomLongStream = secureRandom.longs();
DoubleStream randomDoubleStream = secureRandom.doubles();
你也可以指定流的大小:
IntStream intStream = secureRandom.ints(streamSize);
或者指定流的起始值和边界值(包含起始值,不包含边界值):
IntStream intStream = secureRandom.ints(streamSize, originValue, boundValue);
还可以生成随机字节数组:
byte[] values = new byte[124];
secureRandom.nextBytes(values);
4. 选择算法
默认情况下,SecureRandom
使用的是 SHA1PRNG
算法来生成随机数。你也可以通过调用 getInstance()
方法显式指定其他算法:
SecureRandom secureRandom = SecureRandom.getInstance("NativePRNG");
使用 new SecureRandom()
相当于调用 SecureRandom.getInstance("SHA1PRNG")
。
Java 中支持的随机数生成算法可以参考 官方文档。
5. 种子(Seed)
每个 SecureRandom
实例在初始化时都会带有一个种子(seed)。这个种子是生成随机值的基础,并且每次生成新值时都会被重新混合。
使用 new
关键字或调用 SecureRandom.getInstance()
会从 /dev/urandom
获取默认种子(在类 Unix 系统中)。
你可以通过构造函数传入自定义种子:
byte[] seed = getSecureRandomSeed();
SecureRandom secureRandom = new SecureRandom(seed);
或者通过 setSeed()
方法设置种子:
byte[] seed = getSecureRandomSeed();
secureRandom.setSeed(seed);
⚠️ 注意:设置种子并不能保证生成的随机数序列是确定的,因为 SecureRandom
会将你提供的种子与多个熵源混合,以增强不可预测性。与普通伪随机数生成器不同,它的设计初衷就是即使设置了种子,也保持非确定性行为,从而确保安全性。
6. 小结
本文我们介绍了 Java 中 SecureRandom
的基本使用方法,包括:
✅ 如何生成各种类型的随机值
✅ 如何选择不同的算法
✅ 种子的作用以及设置方式
✅ 为什么 SecureRandom
更适合用于安全场景
如果你的应用涉及密码学操作、安全认证、令牌生成等场景,**务必使用 SecureRandom
而不是 Random
**。
完整的示例代码可以在 GitHub 仓库 中找到。