【问题标题】:What's the best way to create a "good" SecureRandom?创建“好” SecureRandom 的最佳方法是什么?
【发布时间】:2017-04-13 06:29:39
【问题描述】:

有很多问题询问 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?

【问题讨论】:

    标签: java security random-seed java-security secure-random


    【解决方案1】:

    基本上,最好的答案是:你不知道。您最好将选择权留给专家并使用new SecureRandom()。这将通过具有最高优先级的提供者检索第一个随机数生成器。

    存在哪些提供程序以及哪个提供程序具有优先级取决于运行时(IBM 和 Android 也有与 Java 兼容的运行时)。运行时配置也可能因操作系统而异,即使对于标准 JDK。

    在虚拟机上,您应该安装特定 VM 管理器的操作系统特定客户端工具集;这通常允许客户端操作系统从主机操作系统播种。 SecureRandom 通常依赖主机提供种子甚至随机数据。但是,如果主机无法成功播种自己,那么 Java 运行时也将无法播种,并且在虚拟主机上创建的“随机数据”可能会重复。

    来自the JCA documentation

    所有 Java SE 实现都使用无参数构造函数提供默认 SecureRandomnew SecureRandom()。此构造函数遍历已注册安全提供程序的列表,从最喜欢的提供程序开始,然后从支持SecureRandom 随机数生成器 (RNG) 算法的第一个提供程序返回一个新的SecureRandom 对象。如果没有提供程序支持 RNG 算法,则它返回一个使用来自 SUN 提供程序的 SHA1PRNG 的 SecureRandom 对象。


    绝对没有必要自己“播种”算法。调用getSeed() 将尝试从运行时检索种子。这可能会耗尽随机池,就像getInstanceStrong() 一样,导致您的应用程序可能还有其他应用程序被阻塞,直到熵变得可用。 SecureRandom 实现将自己播种 - 希望以最好的方式 - 如果您不提供种子。请注意,在大多数(现代)实现中,提供的种子混入随机池中,最初由例如操作系统;您应该假设已提供相同种子的两个实例将生成相同的随机序列,即使在测试期间也不会,即使您明确指定 "SHA1PRNG" 也不会。

    如果使用new SecureRandom() 导致阻塞,那么您需要确保您的应用程序不直接使用/dev/random,从而耗尽熵池。如果没有并且仍然阻塞,则 /dev/random 可能行为不端。


    要检索长期密钥材料,您还可以使用SecureRandom.getInstanceStrong()。不过,您通常不应该使用它; SecureRandom 对于大多数用例来说应该足够强大。如果您使用getInstanceStrong() 方法,您可能会耗尽操作系统的熵池。


    最好不要使用"SHA1PRNG"。即使所有运行时都有一个实现,it is not an implementation requirement:

    [1] 不需要特定的配置类型、策略类型或 SecureRandom 算法;但是,必须提供特定于实现的默认值。

    请注意,Android 首先使用了不安全的 "SHA1PRNG" 实现,随后被 OpenSSL 原生代码取代。基本上,实现取决于使用了哪个 RNG。问题是 SHA1PRNG 的算法甚至还没有被 Sun 指定,所以不可能依赖算法的任何细节,即使默认实现似乎是安全的。

    【讨论】:

      【解决方案2】:

      我相信,除非你有特殊要求,否则都足够好。

      getSeed() 的文档说:

      仅包含此方法是为了向后兼容。呼叫者,召集者 鼓励使用替代的 getInstance 方法之一 获取一个 SecureRandom 对象,然后调用 generateSeed 方法 从该对象获取种子字节。

      您当然可以完全按照说明进行操作,但我不确定您的其他示例是否有意义。

      我不记得在哪里,但我很久以前就读到过,最好明确地给出算法。所以我通常这样做

      SecureRandom.getInstance("SHA1PRNG")
      

      对于SHA1算法; PRNG 用于伪随机数生成器。虽然 SHA1 已被用于一般加密目的,但有人告诉我,当您想将它们用作加密密钥时,它仍然适用于随机数。

      【讨论】:

        猜你喜欢
        • 2017-08-06
        • 2022-01-05
        • 1970-01-01
        • 2014-12-10
        • 2020-03-03
        • 2016-04-13
        • 2012-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多