问题描述
我需要生成加密性强的随机数和字节数组.为此,我使用了 Java 的 SecureRandom
类.但我不确定根据加密强度选择哪种 PRNG 算法.
I need to generate cryptographically strong random numbers and byte arrays. For this purpose, I'm using Java's SecureRandom
class. But I'm not sure to choose which PRNG algorithm in terms of their cryptographic strength.
以下哪个实例会产生更不可预测的数字?或者他们是平等的?
Which of the following instances generates a more unpredictable numbers? Or are they equal?
SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")
此外,我们可以使用SUN"提供程序生成这些实例(例如 SecureRandom.getInstance("SHA1PRNG", "SUN")
).这有什么不同吗?
Moreover, we are able to generate these instances with "SUN" provider (e.g. SecureRandom.getInstance("SHA1PRNG", "SUN")
). Do this make a difference?
提前致谢.
推荐答案
TL;DR:使用 new SecureRandom()
当您不确定时,让系统来解决.可能使用 SecureRandom.getInstanceStrong()
用于长期密钥生成.
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.
不要期望随机数生成器在运行时应用程序中生成特定的输出序列,即使您自己播种也是如此.
Do not expect a random number generator to generate a specific output sequence within a runtime application, not even if you seed it yourself.
对于随机数生成器,总是很难说哪个是最好的.Linux 和大多数 Unix 都有一个经过深思熟虑的随机数生成器,所以使用 /dev/random
或 /dev/urandom
也没有什么坏处,即 "NativePRNG"代码>.使用
/dev/random
的问题是它会阻塞直到有足够的熵可用.因此,除非您对密钥生成有一些特殊要求,否则我建议您不要这样做.
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/random
or /dev/urandom
, i.e. "NativePRNG"
. Problem with using /dev/random
is 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.
"SHA1PRNG"
使用哈希函数和计数器以及种子.算法比较简单,但是描述的不是很好.它通常被认为是安全的.由于它仅在启动期间从其中一个系统生成器中播种,因此需要较少的内核调用,因此它可能会减少资源密集型 - 在我的系统上,它的运行速度大约是 "NativePRNG"
的 9 倍(配置为使用 /dev/urandom
).两者似乎都只对我的双核 Ubuntu 笔记本电脑的一个核心征税(一次,它经常从一个核心切换到另一个核心,这可能是内核调度的罪魁祸首).如果您需要高性能,请选择这个,尤其是当 /dev/urandom
设备在特定系统配置上运行缓慢时.
"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/urandom
device is slow on the specific system configuration.
请注意,retired Apache Harmony 实现中的 "SHA1PRNG"
与 SUN 提供程序中的不同(Oracle 在标准 Java 中使用SE 实施).Jakarta 中的版本也用于旧版本的 Android.虽然我无法进行全面审查,但它看起来不是很安全.
Note that the "SHA1PRNG"
present in the retired Apache 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.
我并没有错,SHA1PRNG 已被证明不是伪随机的版本 <4.2.2 及更多 这里.
and I wasn't half wrong about this, SHA1PRNG has been shown not to be pseudo-random for versions < 4.2.2 and more here.
请注意,"SHA1PRNG"
不是 Java SE 的实现要求.在大多数运行时它都会存在,但直接从代码中引用它会降低您的代码的可移植性.
Beware that "SHA1PRNG"
is not an implementation requirement for Java SE. On most runtimes it will be present, but directly referencing it from code will make your code less portable.
现在(从 Java 9 开始)OpenJDK 和 Oracle JDK 还包含多个实现,简称为 "DRBG"
.这实现了 NIST 在 SP-108 中指定的动态随机位生成器列表.这些也不是 Java 实现要求.但是,如果需要符合 FIPS 标准的随机数生成器,则可以使用它们.
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.
但是,他们并没有改变这里的建议;如果开发人员认为这些比默认实现更好,那么他们只会将其设为默认实现.SecureRandom
的合约没有改变:它只需要生成随机数.过去已经对默认算法进行了更改.
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 SecureRandom
doesn't change: it is simply required to generate random numbers. Changes to the default algorithm have already been made in the past.
一般来说,要求特定的提供者也不是一个好主意.指定提供者可能会损害互操作性;例如,并非每个 Java 运行时都可以访问 SUN 提供程序——Android 肯定没有.它还使您的应用程序在运行时的灵活性降低,即您不能将提供程序放在列表中更高的位置并使用它.
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.
因此,仅当您依赖某个提供商提供的功能时,才需要指明该提供商.例如,如果您有生成随机数的特定硬件设备或已通过 FIPS 认证的加密库,您可能需要指定提供程序.如果您必须指定提供程序,最好将算法/提供程序作为您的应用程序的配置选项.
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.
这个Android 开发者安全博客.
因此,请尽量避免选择任何特定的随机生成器.相反,只需使用空参数构造函数:new SecureRandom()
让系统选择最佳的随机数生成器.可以使用新的可配置
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.
不要缓存 SecureRandom 的实例
,只需让它们最初自己播种并让VM处理它们.我没有看到操作上有明显的不同.
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
:
作为一般警告,我强烈建议不要将随机数生成器用于随机数生成以外的任何事情.即使您可以自己播种,即使您选择 Sun 的 SHA1PRNG,也不要指望能够从随机数生成器中提取相同的随机数序列.所以不要将它用于从密码中派生密钥,仅举一个例子.
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 not use it for key derivation from passwords, to name one example.
如果您确实需要重复序列,则使用流密码并将种子信息用于密钥和 IV.加密由零组成的明文以检索伪随机值的密钥流.或者,您可以使用可扩展输出函数 (XOF),例如 SHAKE128 或 SHAKE256(如果可用).
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).
如果可用的 RNG 提供的性能不足并且安全不是问题,您可能需要考虑使用不同的非安全随机数生成器来代替 SecureRandom
.SecureRandom
实现不会像 Mersenne Twister 算法或 Random
类.这些已针对简单性和速度而非安全性进行了优化.
You may want to consider a different, non-secure random number generator instead of SecureRandom
if the available RNG's deliver insufficient performance and if security is not an issue. No SecureRandom
implementation will be as fast as non secure random number generators such as the Mersenne Twister algorithm or the algorithm implemented by the Random
class. Those have been optimized for simplicity and speed rather than security.
可以扩展 SecureRandom
类并将确定性的种子随机实现插入到库调用中.这样,库检索具有明确定义输出的伪随机数生成器.然而应该注意,随机数生成器可以由算法以不同的方式使用.例如.RSA 可能会切换到更好的优化方式来查找素数,并且 DES 密钥可以通过调整或直接计算的奇偶校验位生成.
It is possible to extend the SecureRandom
class and 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 与 NativePRNG 与 SHA1PRNG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!