Java SecureRandom 与 NativePRNG 对比 SHA1PRNG

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27622625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:43:37  来源:igfitidea点击:

SecureRandom with NativePRNG vs SHA1PRNG

javarandomcryptographyprng

提问by ovunccetin

I need to generate cryptographically strong random numbers and byte arrays. For this purpose, I'm using Java's SecureRandomclass. But I'm not sure to choose which PRNG algorithm in terms of their cryptographic strength.

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

Which of the following instances generates a more unpredictable numbers? Or are they equal?

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

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

Moreover, we are able to generate these instances with "SUN" provider (e.g. SecureRandom.getInstance("SHA1PRNG", "SUN")). Do this make a difference?

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

Thanks in advance.

提前致谢。

采纳答案by Maarten Bodewes

TL;DR: Use new SecureRandom()when you're not sure and let the system figure it out. Possibly use SecureRandom.getInstanceStrong()for long term key generation.

TL;DR:new SecureRandom()当您不确定时使用并让系统解决它。可能SecureRandom.getInstanceStrong()用于长期密钥生成。

Do not expect a random number generator to generate a specific output sequence within a runtime application, not even if you seed it yourself.

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



With random number generators it is always hard to say which is best. Linux and most Unixes have a pretty well thought out random number generator, so it doesn't hurt to use /dev/randomor /dev/urandom, i.e. "NativePRNG". Problem with using /dev/randomis that it blocks until enough entropy is available. So I would advice against it unless you've got some special requirements with regards to key generation.

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



"SHA1PRNG"uses a hash function and a counter, together with a seed. The algorithm is relatively simple, but it hasn't been described well. It is generally thought of to be secure. As it only seeds from one of the system generators during startup and therefore requires fewer calls to the kernel it is likely to be less resource intensive - on my system it runs about 9 times faster than the "NativePRNG"(which is configured to use /dev/urandom). Both seem to tax only one core of my dual core Ubuntu laptop (at a time, it frequently switched from one core to another, that's probably kernel scheduling that's which is to blame). If you need high performance, choose this one, especially if the /dev/urandomdevice is slow on the specific system configuration.

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

Note that the "SHA1PRNG"present in the retiredApache Harmony implementation is different from the one in the SUN provider (used by Oracle in the standard Java SE implementation). The version within Jakarta was used in older versions of Android as well. Although I haven't been able to do a full review, it doesn't look to be very secure.

请注意,已停用的Apache Harmony 实现中的"SHA1PRNG"存在与 SUN 提供者(Oracle 在标准 Java SE 实现中使用)中的不同。Jakarta 中的版本也用于旧版本的 Android。虽然我还没有能够做一个完整的,但它看起来不是很安全。

EDIT: and I wasn't half wrong about this, SHA1PRNG has been shown not to be pseudo-random for versions < 4.2.2and more here.

编辑:我不是这个半错,SHA1PRNG已经证明不是伪随机的版本<4.2.2在这里

Beware that "SHA1PRNG"is notan implementation requirement for Java SE. On most runtimes it will be present, but directly referencing it from code will make your code less portable.

要注意的是"SHA1PRNG"不是对Java SE的实现要求。在大多数运行时它都会出现,但直接从代码中引用它会使你的代码不那么可移植。



Nowadays (Java 9 onwards) the OpenJDK and Oracle JDK also contain multiple implementations that are simply called "DRBG". This implements a list of Dynamic Random Bit Generators specified by NIST in SP-108. These are not Java implementation requirements either. They could however be used if a FIPS compliant random number generator is required.

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

However, they do not change the recommendations here; if the developers thought that these were better than the default implementation then they would simply have made it the default. The contract of SecureRandomdoesn't change: it is simply required to generate random numbers. Changes to the default algorithm have already been made in the past.

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



In general it's not a good idea to require a specific provider either. Specifying a provider may hurt interoperability; not every Java runtime may have access to the SUN provider for instance - Android certainly hasn't. It also makes your application less flexible at runtime, i.e. you cannot put a provider higher in the list and use that instead.

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

So only indicate a provider if you are dependent on one of the features that it supplies. For instance, you might want to specify a provider if you have a specific hardware device that generates the randoms, or a cryptographic library that has been FIPS certified. It's probably a good idea to make the algorithm/provider a configuration option for your application if you have to specify a provider.

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

The idea of not specifying a provider is also present in this Android developer Security Blog.

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



So try and refrain from choosing any specific random generator. Instead, simply go for the empty argument constructor: new SecureRandom()and let the system choose the best random number generator. It is possible to use the new configurable SecureRandom.getInstanceStrong()in Java 8 and higher if you have any specific requirements for e.g. long term key generation.

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

Don't cache instances of SecureRandom, just let them seed themselves initially and let the VM handle them. I did not see a noticeable difference in operation.

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



When not to use SecureRandomat all:

什么时候不使用SecureRandom

As a general warning I strongly advice against using the random number generator for anything other than random number generation. Even if you can seed it yourself and even if you choose Sun's SHA1PRNG, don't count on being able to extract the same sequence of random numbers from the random number generator. So do notuse it for key derivation from passwords, to name one example.

作为一般警告,我强烈建议不要将随机数生成器用于随机数生成以外的任何事情。即使您可以自己播种,即使您选择 Sun 的 SHA1PRNG,也不要指望能够从随机数生成器中提取相同的随机数序列。所以千万不能使用它从密码密钥导出到仅举一例。

If you do require a repeating sequence then use a stream cipher and use the seed information for the key and IV. Encrypt plaintext consisting of zeros to retrieve the key stream of pseudo random values. Alternatively you could use a extendable-output function (XOF) such as SHAKE128 or SHAKE256 (where available).

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

You may want to consider a different, non-secure random number generator instead of SecureRandomif the available RNG's deliver insufficient performance and if security is not an issue. No SecureRandomimplementation will be as fast as non secure random number generators such as the Mersenne Twister algorithm or the algorithm implemented by the Randomclass. Those have been optimized for simplicity and speed rather than security.

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

It is possible to extend the SecureRandomclassand insert a deterministic, seeded random implementation into a library call. That way the library retrieves a pseudo random number generator with well defined output. It should however be noted that the random number generator may be used in different ways by algorithms. E.g. RSA may switch to a better optimized way of finding primes and DES keys may be generated with adjusted or directly calculated parity bits.

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

回答by nitishagar

As from a ref. here:

从参考。在这里

Native PRNG implementation for Solaris/Linux. It interacts with /dev/random and /dev/urandom, so it is only available if those files are present. Otherwise, SHA1PRNG is used instead of this class.

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

The SUNprovider might be used as default (mainly dependent on the order of the provider which is present).

SUN提供者可被用作默认(主要取决于其存在的提供者的数量级上)。