Oracle 的 java.security.SecureRandom 的随机性有多安全

信息安全 爪哇 随机的
2021-09-06 03:26:23

过去一年有很多关于密码学中可利用的弱点的新闻,这些弱点源于弱随机数生成器。在某些情况下,这是开发人员的疏忽,在其他情况下,是情报组织故意破坏安全 RNG 生成的标准

Oracle 的 JavaVM 中使用SecureRandom随机数生成器的实现如何?当您不指定一个时,它使用什么算法?该算法及其实现是否足够安全以用于密码学?

1个回答

JDK 完整源代码(不仅是标准类,还包括 Sun 特定类和 C++ 本机代码)曾经在“研究许可”下可用,我的磁盘上有一个副本,用于 JDK 1.6(我假设现在你会去 OpenJDK)。

我们看到创建一个java.security.SecureRandom实例意味着调用默认的 PRNG,它恰好是 Sun 特定的类sun.security.provider.SecureRandom

PRNG 是从中播种sun.security.provider.SeedGenerator,反过来将尝试依赖操作系统提供的内容,即/dev/urandom/dev/random在类 Unix 系统(如 Linux)CryptGenRandom()上,Windows 上的 CryptoAPI。如果这些东西不可用(或从 JVM 的配置中停用),则将通过计时操作系统在线程之间切换上下文的速度来提取种子;这是一种后备机制,很少(如果有的话)触发。

种子使用似乎是基于 SHA-1 的自定义自制 PRNG 进行扩展。它是这样工作的:

  • 有一个 160 位的状态s,它是 20 个字节,并且通过应用 little-endian 约定也被解释为模2 160的整数。
  • 输出由 20 字节的块产生。
  • 要生成下一个块c
    • c = SHA-1( s )
    • s = s + c + 1 mod 2 160

有一种机制可以确保s在某些时候确实发生了变化;如果更新后s似乎没有改变,那么它的第一个字节被强制递增。这永远不会被调用;这种情况发生的概率是2 -160,并且用特殊的种子强制它需要打破 SHA-1 的原像抗性,我们不知道该怎么做。

从密码学上讲,这并不可怕。平均而言,它应该在大约2 80 个块之后达到一个周期,并且该周期应该具有相同的平均长度;这是很多(大约 2400 亿千兆字节),所以这很好。如果 SHA-1 是随机预言机,那么只要攻击者不能枚举 160 位空间(实际上他们不能)并且给定的种子不用于产生超过 2400 亿千兆字节(它不会,不会在任何合理甚至不合理的时间内)。我们知道 SHA-1不是随机预言机,但它看起来仍然足够随机。

就我个人而言,我不认为这个 PRNG 对加密使用有问题。它没有“魔法常数”,因此不太可能被后门。它的一个不好的部分是它是非标准的,因此未被充分研究。


如果(当)我需要在 Java 中具有对正式密码学来说足够好的随机性(即好,并且对于监管目的也明显java.security.SecureRandom好),那么我用它来生成一个初始种子(至少 16 个字节),我然后运行 ​​HMAC_DRBG(在NIST SP800-90A中指定)(同一出版物包含险恶名声的 Dual_EC_DRBG,但 HMAC_DRBG 仍然被密码学家认为是好的和干净的)。