【问题标题】:Should I seed a SecureRandom?我应该播种 SecureRandom 吗?
【发布时间】:2011-11-28 07:34:22
【问题描述】:

在我们的代码库中找到以下代码:

public static final int DEFAULT_LENGTH = 16;
private static SecureRandom SR;
static
{
   try
   {
      SecureRandom sd0 = new SecureRandom();
      SR = new SecureRandom(sd0.generateSeed(DEFAULT_LENGTH * 2));
   }
   catch (Exception e){}
}

这里创建了一个默认的SecureRandom,然后它用于为另一个种子创建种子,该种子将在课程中稍后使用。这真的有必要吗?第二个是否比第一个更好,因为这样做了?

第二次生成种子时,给出字节数,这重要吗? SecureRandom 种子的字节数与另一个可能更好或更差?用于播种它的字节数是否应该与它的用途相对应?

如果未调用 setSeed,则第一次调用 nextBytes 将强制 SecureRandom 对象自行播种。如果之前调用了 setSeed,则不会发生这种自播。 - javadoc

自播还不够好吗?是否取决于它的用途?


注意:对于某些上下文,它用于为存储在数据库中的内容创建随机 id 的类中。

【问题讨论】:

    标签: java random


    【解决方案1】:

    我认为这完全没有必要,因为正如您引用的 Javadoc 明确指出的那样:默认构造的 SecureRandom 实例自己播种。写这篇文章的人可能不知道。

    它们实际上还可能通过强制使用可能不适合 RNG 实施的固定种子长度来降低安全性。

    最后,假设 sn-p 未更改,无声异常吞咽也不是很好的编码风格。

    【讨论】:

    • SecureRandom 只附加自定义种子,它从不替换。
    • 是的,我想知道吞咽是否正常。这些行甚至可以引发异常吗?也许如果根本没有安全提供者?但这会发生吗?
    • @Serdalis 你这是什么意思?它是否总是生成自己的种子,然后当您在构造函数或setSeed 方法中发送种子时,它只会附加到它自己已经生成的种子?
    • 是的,它永远不会替换它的种子,你只能用你输入的内容来扩充它。
    • 其实这并不完全正确。一旦设置了种子,它将永远不会替换种子,但是如果没有设置明确的种子,则自播仅在第一次调用以生成随机数时发生(这是必要的,否则您无法设置 SecureRandom 来生成一组特定的输出数字)。
    【解决方案2】:

    这不仅完全没有必要,实际上还可以提高 SecureRandom 对象生成的数字的可预测性。

    没有明确种子集的 SecureRandom 将自行设置种子。它使用高度随机的数据源来执行此操作,并且非常安全。您的代码示例中的第一个 SecureRandom 将使用这样的种子。

    第二个通过产生 256 个随机位从第一个播种。假设使用系统默认的 SHA1PRNG,这就足够了。它使用 160 位状态,因此 256 个随机位将完全满足它的要求。但是假设现在有人认为这还不够,并将默认值切换为 SHA512PRNG(他们甚至可以通过更改 java 的安全属性来查看您的代码)。现在你提供给它的种子位太少了:只有它需要的一半。

    摆脱它,只使用自播种对象,除非您拥有比系统可用的更好的种子数据源。

    【讨论】:

    • 更糟糕的是 - 代码完全荒谬。自播是足够安全的——那么就不需要播种。或者它不是 - 那么代码也不会改善问题,因为它依赖于 sd0 完成的自我播种来为 SR 提供​​种子。 8-()
    【解决方案3】:

    避免使用new SecureRandom();时的默认算法

    改为:

    SecureRandom.getInstance("SHA1PRNG", "SUN");
    

    如果有人更改默认算法(如 @Jules 所述),您不会受到影响。


    针对 Android 编辑:

    对于android,看看:

    在 Android 上,我们不建议指定提供程序。一般来说, 对 Java Cryptography Extension (JCE) API 的任何调用,指定一个 仅当提供者包含在 应用程序,或者如果应用程序能够处理可能的 ProviderNotFoundException。

    ...

    在 Android N 中,我们不推荐使用 SHA1PRNG 算法和 Crypto 提供程序一并

    【讨论】:

    • 感谢 Nate,确实更准确! "SHAPRNG" => "SHA1PRNG"
    • 但这正是朱尔斯所警告的!如果有人将默认算法更改为更安全,使用这种硬编码算法的 Java 应用程序将无法适应。
    • 真的!但当时,这是我第一次或第二次回答,所以我没有足够的声誉来添加评论。此外,没有其他答案提供“不使用默认算法”的确切代码行,因此我的答案;)
    • 不应再使用“SHA1PRNG”!详情见这里:android-developers.googleblog.com/2016/06/…
    • @phw 感谢您的链接。我的回答是关于不使用默认实现,而不是关于特定的“提供者”。我以 SUN 为例。您的链接专门讨论了与加密提供商弃用 SHA1PRNG:getInstance("SHA1PRNG", "crypto")
    【解决方案4】:

    只是这个答案的附录。根据 Google 的说法,如果您在 android 中使用此代码,您绝对应该使用像 /dev/urandom 或 /dev/random 这样的高熵源来播种 SecureRandom。

    即使下面的帖子现在已经有一年了,也许这已经被纠正了,但我无法确认是否正确。

    https://plus.google.com/+AndroidDevelopers/posts/YxWzeNQMJS2

    编辑:

    似乎该类的默认行为现在是帖子中指定的行为,因此再次认为不需要播种:

    http://developer.android.com/reference/java/security/SecureRandom.html

    【讨论】:

      【解决方案5】:

      很遗憾,javadoc 没有说明最小种子大小“DEFAULT_LENGTH”是多少才能达到算法设计的预期安全级别,即使对于某些默认实现也是如此。 :(

      本质上,安全性取决于真正的随机;没有什么比“没有外部数据的算法自己播种”。除非种子生成器的输入被公开,否则不可能证明任何安全级别。

      真正随机的提供者是 1.) https://www.random.org/ 2.) VeraCrypt 等工具从鼠标运动中提取白噪声。

      如果您的目标是真正的安全,您会将来自匿名随机生成器的数字与自我验证的白噪声相结合。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        • 2017-12-31
        • 2019-02-03
        • 1970-01-01
        相关资源
        最近更新 更多