使用 NativePRNG 与 SHA1PRNG 的 SecureRandom

新手上路,请多包涵

我需要生成加密强度高的随机数和字节数组。为此,我正在使用 Java 的 SecureRandom 类。但我不确定根据密码强度选择哪种 PRNG 算法。

以下哪个实例会产生更不可预测的数字?或者他们是平等的?

 SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")

此外,我们能够使用“SUN”提供程序生成这些实例(例如 SecureRandom.getInstance("SHA1PRNG", "SUN") )。这有什么不同吗?

提前致谢。

原文由 ovunccetin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.2k
2 个回答

TL;DR:当您不确定时使用 new SecureRandom() 并让系统找出答案。可能使用 SecureRandom.getInstanceStrong() 进行长期密钥生成。

不要指望随机数生成器在运行时应用程序中生成特定的输出序列,即使您自己播种也不行。


对于随机数生成器,总是很难说哪个是最好的。 Linux 和大多数 Unix 都有一个经过深思熟虑的随机数生成器,所以使用 /dev/random/dev/urandom 并没有什么坏处,即 "NativePRNG" 使用 /dev/random 的问题是它会阻塞,直到有足够的熵可用。所以我建议不要这样做,除非您对密钥生成有一些特殊要求。


"SHA1PRNG" 使用散列函数和计数器,以及种子。算法比较简单,但是一直没有很好的描述。它通常被认为是安全的。因为它只在启动期间从其中一个系统生成器播种,因此需要更少的内核调用,所以它可能占用更少的资源——在我的系统上,它的运行速度比 "NativePRNG" (这是配置为使用 /dev/urandom )。两者似乎都只对我的双核 Ubuntu 笔记本电脑的一个核心征税(一次,它经常从一个核心切换到另一个核心,这可能是内核调度的罪魁祸首)。如果您需要高性能,请选择这个,尤其是当 /dev/urandom 设备在特定系统配置上速度慢时。

请注意, 退役 的 Apache Harmony 实现中的 "SHA1PRNG" 与 SUN 提供程序中的不同(甲骨文在标准 Java SE 实现中使用)。 Jakarta 中的版本也用于旧版本的 Android。虽然我无法进行全面审查,但它看起来并不是很安全。

编辑:我对此没有半点错误, SHA1PRNG 已被证明对于版本 < 4.2.2 和更多版本不是伪随机的

请注意 "SHA1PRNG" 不是 Java SE 的实现要求。在大多数运行时它都会存在,但直接从代码中引用它会使代码的可移植性降低。


如今(从 Java 9 开始)OpenJDK 和 Oracle JDK 还包含多个简单称为 "DRBG" 的实现。这实现了 NIST 在 SP-108 中指定的动态随机位生成器列表。这些也不是 Java 实现要求。但是,如果需要符合 FIPS 的随机数生成器,则可以使用它们。

但是,他们不会更改此处的建议;如果开发人员认为这些比默认实现更好,那么他们只会将其设为默认实现。 SecureRandom 的合同没有改变:它只是需要生成随机数。过去已经对默认算法进行了更改。


一般来说,要求特定的提供者也不是一个好主意。指定提供者可能会损害互操作性;例如,并非每个 Java 运行时都可以访问 SUN 提供程序——Android 肯定没有。它还会降低您的应用程序在运行时的灵活性,即您不能将提供者放在列表中较高的位置并使用它来代替。

因此,仅当您依赖提供者提供的其中一项功能时才指明提供者。例如,如果您有生成随机数的特定硬件设备或已通过 FIPS 认证的加密库,您可能希望指定提供程序。如果您必须指定提供程序,那么让算法/提供程序成为您的应用程序的配置选项可能是个好主意。

不指定提供商的想法也出现在这个 Android 开发人员安全博客 中。


因此,请尽量避免选择任何特定的随机生成器。相反,只需使用空参数构造函数: new SecureRandom() 并让系统选择最佳随机数生成器。如果您对长期密钥生成有任何特定要求,则可以在 Java 8 及更高版本中使用新的可配置 SecureRandom.getInstanceStrong()

不要缓存 SecureRandom 的实例,只是让它们最初播种并让 VM 处理它们。我没有看到操作上的明显差异。


什么时候不使用 SecureRandom

作为一般性警告,我强烈建议不要将随机数生成器用于随机数生成以外的任何用途。即使您可以自己播种,即使您选择 Sun 的 SHA1PRNG, _也不要指望能够从随机数生成器中提取相同的随机数序列_。因此, 不要 将它用于从密码派生密钥,仅举一个例子。

如果您确实需要重复序列,则使用流密码并将种子信息用于密钥和 IV。加密由零组成的明文以检索伪随机值的密钥流。或者,您可以使用可扩展输出函数 (XOF),例如 SHAKE128 或 SHAKE256(如果可用)。

如果可用的 RNG 提供的性能不足并且安全性不是问题,您可能需要考虑使用不同的、非安全的随机数生成器而不是 SecureRandom 。没有 SecureRandom 实现将与非安全随机数生成器一样快,例如 Mersenne Twister 算法或 Random 类实现的算法。这些已针对简单性和速度而不是安全性进行了优化。

可以 扩展 SecureRandom 并将确定性的、种子随机实现插入到库调用中。通过这种方式,库可以检索具有明确输出的伪随机数生成器。然而,应该注意的是,算法可以以不同的方式使用随机数生成器。例如,RSA 可能会切换到一种更好的优化方式来查找素数,并且 DES 密钥可能会使用调整后的或直接计算的奇偶校验位来生成。

原文由 Maarten Bodewes 发布,翻译遵循 CC BY-SA 4.0 许可协议

作为参考。 这里

Solaris/Linux 的本机 PRNG 实现。它与 /dev/random 和 /dev/urandom 交互,因此只有当这些文件存在时它才可用。否则,使用 SHA1PRNG 代替此类。

SUN 提供程序可能用作默认提供程序(主要取决于提供程序存在的顺序)。

原文由 nitishagar 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题