java SecureRandom:初始化一次还是每次需要?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/295628/
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-10-29 11:48:08  来源:igfitidea点击:

SecureRandom: init once or every time it is needed?

javasecurityrandomcryptography

提问by ngn

Our team is using a SecureRandom to generate a list of key pairs (the SecureRandom is passed to a KeyPairGenerator). We cannot agree on which of the following two options to use:

我们的团队正在使用 SecureRandom 来生成密钥对列表(SecureRandom 被传递给 KeyPairGenerator)。我们无法就使用以下两个选项中的哪一个达成一致:

  1. Create a new instance every time we need to generate a key pair

  2. Initialize a static instance and use it for all key pairs

  1. 每次我们需要生成密钥对时,都会创建一个新实例

  2. 初始化一个静态实例并将其用于所有密钥对

Which approach is generally better and why?

哪种方法通常更好,为什么

ADDED: My gut feeling is that the second option is more secure. But my only argument is a theoretical attack based on the assumption that the pseudorandomness is derived from the current timestamp: someone may see the creation time of the key pair, guess timestamps in the surrounding time interval, compute the possible pseudorandom sequences, and obtain the key material.

补充:我的直觉是第二种选择更安全。但我唯一的论点是基于伪随机性来自当前时间戳的假设的理论攻击:有人可能会看到密钥对的创建时间,猜测周围时间间隔内的时间戳,计算可能的伪随机序列,并获得关键材料。

ADDED: My assumption about determinism based on a timestamp was wrong. That's the difference between Random and SecureRandom. So, it looks like the answer is: in terms of security it doesn't really matter.

补充:我关于基于时间戳的确定性的假设是错误的。这就是 Random 和 SecureRandom 之间的区别。因此,答案似乎是:就安全性而言,这并不重要。

采纳答案by Gowri

Unlike the java.util.Randomclass, the java.security.SecureRandomclass must produce non-deterministic output on each call.

java.util.Random类不同,java.security.SecureRandom类必须在每次调用时产生非确定性输出。

What that means is, in case of java.util.Random, if you were to recreate an instance with the same seed each time you needed a new random number, you would essentially get the sameresult every time. However, SecureRandomis guaranteed to NOT do that - so, creating a single instance or creating a new one each time does notaffect the randomness of the random bytes it generates.

这意味着,在 的情况下java.util.Random,如果每次需要新的随机数时都使用相同的种子重新创建实例,则每次基本上都会得到相同的结果。但是,SecureRandom保证不会这样做 - 因此,每次创建单个实例或创建一个新实例都不会影响它生成的随机字节的随机性。

So, from just normal good coding practices view point, why create too many instances when one will do?

那么,从正常的良好编码实践的角度来看,为什么要创建太多实例呢?

回答by Matthew McCullough

For SecureRandomyou would want to consider occasionally reseeding (using system entropy in most cases) via a call like so:

对于SecureRandom,您可能需要考虑通过如下调用偶尔重新播种(在大多数情况下使用系统熵):

mySecureRandom.setSeed(mySecureRandom.generateSeed(someInt));

so as to give a potential attacker something less than unlimited time to discover your key.

以便给潜在的攻击者一些少于无限时间的时间来发现您的密钥。

There's some great writeups about this consideration at the Justice Leagueblog.

正义联盟博客上有一些关于这个考虑的很棒的文章。

回答by Mitch Wheat

Initialize a static instance and use it for all key pairs. It won't be any more or less random.

初始化一个静态实例并将其用于所有密钥对。它不会或多或少是随机的。

回答by Mitch Wheat

Every SecureRandomgeneration is seeded from some entropy pool. Depending on the OS used, this might be the entropy pool maintained by the OS like /dev/randomon Linux, or might be something that the JVM cooks up. In some earlier implementations, the Sun JVM used to spawn a number of threads and use their timing data to create the seed.

SecureRandom一代都是从某个熵池中播种的。根据所使用的操作系统,这可能是由操作系统维护的熵池,如/dev/random在 Linux 上,或者可能是 JVM 编造的东西。在一些早期的实现中,Sun JVM 过去常常产生多个线程并使用它们的计时数据来创建种子。

Creating a new SecureRandomon every call might cause slow down of the application since creation of the seed might be blocking. Its better to reuse the a statically created instance, but make sure to reseed it after a fixed number random bytes are extracted from it.

SecureRandom在每次调用时创建一个新的可能会导致应用程序变慢,因为种子的创建可能会被阻塞。最好重用静态创建的实例,但确保在从中提取固定数量的随机字节后重新播种。

You may want to create a wrapper over a SecureRandominstance which counts the number of bytes extracted in nextBytesor generateSeedcalls and after a number of bytes, reseeds the internal SecureRandominstance by using system entropy pool.

您可能希望在SecureRandom实例上创建一个包装器,该包装器计算在nextBytesgenerateSeed调用中提取的字节数,并在多个字节之后,SecureRandom使用系统熵池为内部实例重新设定种子。

The wrapper approach however is not possible on Java on Linux since the SecureRandominstance you get from new SecureRandom()is nothing but a wrapper on /dev/randomand every call for nextBytesor generateSeedactually drains the OS entropy pool. On Linux and Solaris, its better to use a JCE provider for SecureRandomcreation.

然而,包装器方法在 Linux 上的 Java 上是不可能的,因为SecureRandom您从 new 获得的实例SecureRandom()只不过是一个包装器,/dev/random并且每次调用nextBytesgenerateSeed实际耗尽操作系统熵池。在 Linux 和 Solaris 上,最好使用 JCE 提供程序进行SecureRandom创建。

回答by Nick Johnson

I would not rely on SecureRandom to be anything other than a cryptographically secure PRNG. The complete quote that Gowri is using from the javadocs is:

我不会依赖 SecureRandom 成为加密安全 PRNG 以外的任何东西。Gowri 在 javadocs 中使用的完整引用是:

Additionally, SecureRandom must produce non-deterministic output and therefore it is required that the seed material be unpredictable and that output of SecureRandom be cryptographically strong sequences as described in RFC 1750: Randomness Recommendations for Security.

此外,SecureRandom 必须产生非确定性输出,因此要求种子材料是不可预测的,并且 SecureRandom 的输出是加密强序列,如 RFC 1750:安全性随机性建议中所述。

It's less than clear from this what the real expectation is - RFC 1750 details the use of hardware to enhance random number generation, but the javadocs say "therefore it is required that the seed material be unpredictable", which would seem to contradict this.

从中不太清楚真正的期望是什么 - RFC 1750 详细说明了使用硬件来增强随机数生成,但 javadoc 说“因此要求种子材料是不可预测的”,这似乎与此矛盾。

The safest assumption to work on is that your implementation of SecureRandom is simply a cryptographically-secure PRNG, and therefore that your keys are no more secure than the random seed that you use. Thus, initializing a new SecureRandom with a new (unique, truly random) seed for each key would be the safest bet.

最安全的假设是您的 SecureRandom 实现只是一个加密安全的 PRNG,因此您的密钥并不比您使用的随机种子更安全。因此,为每个密钥使用新的(唯一的、真正随机的)种子初始化新的 SecureRandom 将是最安全的选择。

回答by Alex Miller

Once should be enough. My experience has also been that initializing SecureRandom type generators can sometimes be slow as well (due to how randomness is achieved), so you should take that into consideration.

一次应该就够了。我的经验也是,初始化 SecureRandom 类型生成器有时也会很慢(由于随机性是如何实现的),所以你应该考虑到这一点。

回答by Jorn

Why would you want to create a new instance every time? It's not like that would be morerandom. I think it would be best to initialize once and use it for all pairs.

为什么每次都想创建一个新实例?这不会随机。我认为最好初始化一次并将其用于所有对。