SecureRandom 的随机数从哪来?setSeed 到底做什么?要不要复用实例?这篇用实测回答(普通随机数算法的对比在前两篇,这篇只看安全随机数;熵的来源是操作系统,本篇没有直接观察系统调用)。
new SecureRandom() 的算法 = NativePRNG,提供者 = SUN SecureRandom.getInstanceStrong() 的算法 = NativePRNGBlocking,提供者 = SUN java.security 里:securerandom.source = file:/dev/random;securerandom.strongAlgorithms = NativePRNGBlocking:SUN,DRBG:SUN 提供者 SUN 提供的 SecureRandom 算法:[DRBG, NativePRNG, NativePRNGBlocking, NativePRNGNonBlocking, SHA1PRNG] DRBG 实例的参数:128,reseed_only,null
SHA1PRNG 两个实例都在第一次使用之前 setSeed(42):输出 d50ac288b90ede2e 与 d50ac288b90ede2e → 完全相同(种子决定了输出) NativePRNG 两个实例都在第一次使用之前 setSeed(42):输出 bb500fa0875fc913 与 39842e47a0e6b5ed → 不同(setSeed 只是补充熵,不决定输出) DRBG 两个实例都在第一次使用之前 setSeed(42):输出 f9544d6ff4c06a9c 与 ac6a1f775eedf440 → 不同(setSeed 只是补充熵,不决定输出) SHA1PRNG 先生成过数据(自己播了种),之后再 setSeed(42):输出 3d18d237fdfe3f97 与 85f28bf50a1afccb → 不同(setSeed 在已播种后只是追加)
NativePRNG 创建+首次使用 15766 µs;nextBytes(32) 平均 221 ns/次;generateSeed(32) 38 µs DRBG 创建+首次使用 1257 µs;nextBytes(32) 平均 223 ns/次;generateSeed(32) 59 µs SHA1PRNG 创建+首次使用 1940 µs;nextBytes(32) 平均 106 ns/次;generateSeed(32) 55 µs NativePRNGNonBlocking 创建+首次使用 195 µs;nextBytes(32) 平均 197 ns/次;generateSeed(32) 15 µs 每次都 new SecureRandom() 再 nextInt():5.0 µs/次(1000 次);复用同一个实例的 nextInt():61 ns/次
100 万个随机字节:1 的比特占 0.5001(理想 0.5000);256 种字节值的卡方统计量 = 262.7(自由度 255,均值 255,标准差约 22.6;落在 255 ± 3 个标准差 ≈ 187~323 之内是正常的) 这只是最粗的合理性检查,不是对随机数质量的证明(没有做 NIST / Dieharder 之类的检验)