SecureRandom:init一次或每次需要init?

时间:2008-11-17 14:03:32

标签: java security random cryptography

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

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

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

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

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

    补充:我对基于时间戳的决定论的假设是错误的。这是Random和SecureRandom之间的区别。因此,看起来答案是:就安全性而言,它并不重要。

7 个答案:

答案 0 :(得分:13)

对于SecureRandom,您可能希望通过这样的调用偶尔重新播种(using system entropy in most cases):

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

以便为潜在的攻击者提供一些不到无限的时间来发现你的密钥。

Justice League博客上有一些关于这个问题的精彩文章。

答案 1 :(得分:10)

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

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

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

答案 2 :(得分:4)

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

答案 3 :(得分:4)

每个SecureRandom代都来自某个熵池。根据所使用的操作系统,这可能是操作系统维护的熵池,如Linux上的/dev/random,或者可能是JVM烹饪的内容。在一些早期的实现中,Sun JVM用于生成许多线程并使用它们的计时数据来创建种子。

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

您可能希望在SecureRandom实例上创建一个包装器,它计算在nextBytesgenerateSeed调用中提取的字节数,并在多个字节之后重新生成内部{{ 1}}实例使用系统熵池。

然而,自从您获得SecureRandom实例以来,在Linux上的Java上无法实现包装器方法 新SecureRandom只是SecureRandom()上的包装器,每次调用/dev/randomnextBytes实际上都会耗尽操作系统熵池。在Linux和Solaris上,最好使用JCE提供程序进行generateSeed创建。

答案 4 :(得分:3)

除了加密安全的PRNG之外,我不会依赖SecureRandom。 Gowri在javadocs中使用的完整引用是:

  

此外,SecureRandom必须   产生非确定性的输出和   因此需要种子   材料是不可预测的   SecureRandom的输出是   密码学上强大的序列   在RFC 1750中描述:随机性   安全建议。

从中可以看出真正的期望是什么 - RFC 1750详述了使用硬件来增强随机数生成,但javadocs说“因此需要种子材料不可预测”,这似乎是矛盾的此

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

答案 5 :(得分:1)

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

答案 6 :(得分:-1)

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