SecureRandom的行为

9

尽管我已经阅读了很多与SecureRandom有关的文章,但是我在Java中使用SecureRandom安全API时遇到了一个疑问。以下是一个例子:

public class SecureRandomNumber {
public static void main(String[] args) throws NoSuchAlgorithmException {

    TreeSet<Integer> secure = new TreeSet<Integer>();
    TreeSet<Integer> unSecure = new TreeSet<Integer>();
    SecureRandom sr = new SecureRandom();
    byte[] sbuf = sr.generateSeed(8);
    ByteBuffer bb = ByteBuffer.wrap(sbuf);
    long d = bb.getLong();
    sr.setSeed(d);

    Random r = new Random();
    r.setSeed(System.nanoTime());
    for (int k = 0; k < 99999; k++) {
        int i = sr.nextInt();
        if (!secure.add(i)) {
            System.out.println("Repeated Secure Random Number");
        } else {
//              System.out.println("************Unique***********");
        }
        int j = r.nextInt();

        if (!unSecure.add(j)) {
            System.out.println("Repeated UnSecure Random Number");
        }
    }
}

当我运行这个程序时,我发现使用SecureRandom几乎没有任何额外的好处,因为它几乎给出了相同的结果。

有人能告诉我我在这里做对了吗?

3个回答

17
你误解了随机数的普遍概念,认为一个随机序列不会重复。相反,它很可能会高概率地出现重复。这种误解实际上用于区分人造“随机”序列和真正随机序列。人类生成的“随机”0和1序列通常会像这样:0、1、0、1、1、0、1、0、0、1、0、1、0等等。而真正的随机序列不会回避重复数字,相同数字出现两次以上是很常见的,好的例子可以从 统计测试 中找到。
两种生成器都有良好的“统计特性”。通常人们认为,加密安全的随机数将产生更“随机”的值,这也是一种常见的误解。实际上,它们的统计概率很可能非常相似,并且在标准统计测试中表现良好。
因此,你需要根据你所需做的事情来选择PRNG或加密安全的PRNG(CSPRNG)。对于蒙特卡罗方法等模拟目的来说,“普通”PRNG完全可以胜任。CSPRNG的额外好处在于不可预测性。因为CSPRNG可以“做更多的事情”,所以它的性能也很可能比普通PRNG差。可以证明,“安全”的伪随机数生成器(PRNG)的概念与能够预测其输出的下一位紧密相关。对于密码安全的伪随机数生成器(CSPRNG),在任何时候预测其输出的下一位都是计算上不可行的。当然,只有在将其种子值视为秘密时才成立。一旦有人发现了种子,整个过程就变得容易预测 - 只需重新计算CSPRNG算法已经生成的值,然后计算下一个值即可。还可以进一步证明,免疫于“下一位预测”实际上意味着没有任何统计测试可以区分CSPRNG的分布和真正的随机均匀分布之间的差异。因此,在PRNG和CSPRNG之间还有另一个区别:虽然良好的PRNG会在许多统计测试中表现出色,但CSPRNG保证在所有测试中表现良好。
使用哪种生成器的经验规则是: - 在“敌对”环境中使用CSPRNG,你不希望外部人能够猜测敏感信息(会话ID,赢取/输掉真钱的在线扑克等)。 - 在友好的环境中使用PRNG,你只需要良好的统计特性,但不关心可预测性(蒙特卡罗模拟,单人扑克与计算机,普通计算机游戏) - 也就是说,如果有人能够成功地预测这些随机数,将不会赢得任何钱或失去生命。

非常感谢您提供如此详细的描述 :) 它真的很有帮助。 - chaosguru
1
此外,CSPRNG 应该对逆推攻击具有免疫力:即使给定其输出的一部分,也无法逆推出先前的输出。它应该对未来或过去的扩展攻击具有免疫力。 - rossum

5

安全和不安全的算法通常会给出几乎相同的结果,你无法从输出中检测到安全漏洞。一个装有无法被撬开的锁的门和一个装有容易被撬开的锁的门看起来非常相似,如果你只是转动把手,两者都无法打开。这就是为什么编写安全代码以及处理加密和认证等问题是编程领域需要专门设计、开发和测试技术的原因之一。


好的,另外根据我阅读的文章,我理解高质量的随机性很重要,而SecureRandom提供了这种随机性。我认为这是唯一但至关重要的优势。 - chaosguru
1
正确。如果你需要它,那你确实需要它。但如果不需要它,你就会因无故付出计算成本。 - David Schwartz

2

SecureRandom不能保证每次生成唯一的随机数。它只是确保在给定先前的数字的情况下,您无法预测下一个随机数。所以,基本上,您正在寻找错误的答案。

让我们用骰子的例子来说明。使用SecureRandom就像使用普通未加载的骰子。每个掷骰子的结果都与之前的掷骰子结果独立。而非安全随机数则使用先前的掷骰子结果来确定下一个结果。(因此,如果您知道上一次掷出的是六,您可以预测下一次的掷骰子结果)。

因此,您基本上必须确定如果用户/黑客/管理员等可以根据先前的随机数列表来预测哪个数字会出现,这是否会对您的应用程序造成问题。(在大多数情况下,这将是一个问题)。如果您只想使用随机数选择要在网页中显示的随机内容,则普通随机数就可以了。如果您想将随机数用于安全、游戏或交易,最好使用SecureRandom。

我不确定,但我认为使用SecureRandom会有很小的开销增加。因此,普通随机数略快。但在大多数情况下,当人们滥用不安全的随机数生成器时,这种速度增加并不值得潜在问题。


但这仍然是一个需要回答的问题。返回2的函数是一个随机函数,只是不是一个好的函数。 ;) - Ids

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接