有很多问题询问 SecureRandom 的特定启动是否“好”,但我找不到经验法则。
创建“良好”随机 SecureRandom 的最佳方法是什么?
// Fast
// Is it a good random?
SecureRandom secureRandom = new SecureRandom()?
// Freezes for a few seconds after being used several times - until getting a random enough seed.
// See http://stackoverflow.com/questions/137212/how-to-solve-performance-problem-with-java-securerandom#comment68934647_137212
// Is it a good random?
SecureRandom secureRandom = new SecureRandom(SecureRandom.getSeed(20))?
// Freezes for a very long time. Waited minutes and still no return :(
SecureRandom secureRandom = new SecureRandom.getInstanceStrong()?
Other?
基本上,最好的答案是:你不知道。你最好把选择权留给专家并使用
new SecureRandom()
。这将由拥有随机数生成器的最高优先级提供商检索第一个随机数生成器。
存在哪些提供程序以及哪一个具有优先级取决于运行时(IBM 和 Android 也有 Java 兼容运行时)。每个操作系统的运行时配置也可能有所不同,即使对于标准 JDK 也是如此。
在虚拟机上,您应该安装特定 VM 管理器的操作系统特定客户端工具集;这通常允许客户端操作系统从主机操作系统播种。
SecureRandom
通常取决于主机提供种子甚至随机数据。然而,如果主机无法成功地自行播种,那么 Java 运行时也将无法做到这一点,并且在虚拟主机上创建的“随机数据”可能会重复。
来自 JCA 文档:
所有 Java SE 实现都使用无参数构造函数提供默认的
:SecureRandom
。此构造函数遍历已注册安全提供程序的列表,从最首选的提供程序开始,然后从第一个支持new SecureRandom()
随机数生成器 (RNG) 算法的提供程序返回一个新的SecureRandom
对象。如果没有一个提供商支持 RNG 算法,则它返回一个使用 SUN 提供商的 SHA1PRNG 的SecureRandom
对象。SecureRandom
完全没有必要自己为算法“播种”。调用
getSeed()
将尝试从运行时检索种子。这可能会耗尽随机性池,就像getInstanceStrong()
一样,导致您的应用程序以及可能的其他应用程序受阻,直到熵变得可用。如果您不提供种子,SecureRandom
实现将自行播种 - 希望以尽可能最好的方式。请注意,在大多数(现代)实现中,提供的种子“混合到”随机池中,最初是由例如操作系统;您不应该假设提供相同种子的两个实例将生成相同的随机序列,即使在测试期间也不应如此,即使您明确指定也不应如此。准确地说,"SHA1PRNG"
的确定性行为特定于 Sun / Oracle 实现,并且还可能依赖于运行时系统的行为。
如果使用 "SHA1PRNG"
导致阻塞,那么您需要确保您的应用程序不会直接使用 new SecureRandom()
,从而耗尽熵池。如果没有并且仍然阻塞,那么 /dev/random
可能行为不当。现代 Linux 内核基本上会使
/dev/random
和 /dev/random
相同;两者都将使用基于从系统和 CPU 收集的熵的确定性 RNG,以防硬件 RNG 可用。
要检索长期密钥密钥材料,您还可以使用
/dev/urandom
。不过,您通常不应该使用它; SecureRandom.getInstanceStrong()
对于大多数用例来说应该足够强大。如果您使用 SecureRandom
方法,您可能会耗尽操作系统的熵池。请注意,在较新的系统上,这种情况不太可能发生。例如,在 Linux 上,
getInstanceStrong()
和 /dev/random
都指向相同的伪随机数生成器。
最好不要使用
/dev/urandom
。即使所有运行时都有一个实现,它不是
:
[1] 不需要特定的配置类型、策略类型或安全随机算法;但是,必须提供特定于实现的默认值。 请注意,Android 首先使用不安全的"SHA1PRNG"
实现,随后被 OpenSSL 本机代码取代。基本上,实现取决于使用哪种 RNG。问题是 SHA1PRNG 的算法甚至还没有被 Sun 指定,因此不可能依赖该算法的任何细节,即使默认实现看起来是安全的。注意 2024-03-02:恕我直言,这仍然是一个很好的答案,但它需要有关符合 NIST 的 DRBG RNG 和扩展 API 的更新。