SecureRandom with NativePRNG vs SHA1PRNG

2022-09-01 00:01:29

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

以下哪个实例生成更不可预测的数字?还是它们是平等的?

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

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

提前致谢。


答案 1

TL;DR:当你不确定时,使用新的SecureRandom(),让系统弄清楚。可能使用SecureRandom.getInstanceStrong()进行长期密钥生成。

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


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


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

请注意,已停用的Apache Harmony实现中存在的“SHA1PRNG”与SUN提供程序中的“SHA1PRNG”(Oracle在标准Java SE实现中使用)中的“SHA1PRNG”不同。雅加达的版本也用于旧版本的Android。虽然我无法进行全面审查,但它看起来不是很安全。

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

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


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

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


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

因此,仅当您依赖于提供程序提供的功能之一时,才指示提供程序。例如,如果您有生成随机数的特定硬件设备或已通过 FIPS 认证的加密库,则可能需要指定提供程序。如果必须指定提供程序,则将算法/提供程序作为应用程序的配置选项可能是一个好主意。

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


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

不要缓存 SecureRandom 的实例,只需让它们最初自行设定种子并让 VM 处理它们即可。我没有看到操作上的明显差异。


何时根本不使用 SecureRandom

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

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

您可能需要考虑使用不同的非安全随机数生成器,而不是如果可用的 RNG 提供的性能不足,并且安全性不是问题。没有一个实现能像非安全随机数生成器(如 Mersenne Twister 算法或 Random 类实现的算法)那样快。这些已经过优化,以实现简单性和速度,而不是安全性。SecureRandomSecureRandom

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


答案 2

从这里的参考文献中可以看出

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

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


推荐