即使在阅读了很多有关SecureRandom的文章之后,我仍然对Java中SecureRandom Security 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并没有任何其他好处,因为它几乎给出了相同的结果。

有人可以让我知道我在这里做对了吗?

最佳答案

通常,您是一个普遍误解随机数的受害者:随机序列并不意味着不能在该序列中重复一个数字。相反,它必须具有很高的概率。这种误解实际上是用来分辨人类从真实的序列中产生的“随机”序列。人类产生的“0”和“1”的“随机”序列可能看起来像这样:
0,1,0,1,1,0,1,0,0,1,0,1,0,....
而真正的随机序列并不难于重复相同的数字两次以上:)一个很好的例子是statistical tests也在寻找重复。
两种生成器都具有良好的“统计特性”
人们也普遍误以为密码安全的随机数会以某种方式产生“更多的随机”值。它们的统计概率可能会非常相似,并且两者在那些标准统计测试中的表现都将非常好。
在哪里使用
因此,实际上,要取决于您要做什么,是选择PRNG还是采用加密安全的PRNG(CSPRNG)。 “正常” PRNG非常适合用于模拟目的,例如蒙特卡罗方法等。CSPRNG的附加好处是具有不可预测性。由于CSPRNG可以“做更多”,因此其性能也将比普通PRNG差。
可以看出,“安全” PRNG的概念与预测其输出的下一位的能力紧密相关。对于CSPRNG,在任何时候预测其输出的下一位在计算上都是不可行的。当然,仅当您将其种子值视为 secret 时,这才成立。一旦有人发现了种子,整个事情就变得容易预测-只需重新计算CSPRNG算法已经生成的值,然后计算下一个值即可。可以进一步证明,不受“下一位预测”的影响实际上意味着,没有任何统计检验可以将CSPRNG的分布与实际的随机均匀分布区分开。因此,PRNG和CSPRNG之间还有另一个区别:尽管一个好的PRNG在许多统计测试中都能表现良好,但CSPRNG在所有测试中都能保证表现良好。
经验法则是在哪里使用

  • 您在“敌对”环境中使用CSPRNG,您不希望外部人员能够猜测敏感信息( session ID,在线货币赢/输的在线扑克,....)
  • 和PRNG处于一个仁慈的环境中,您只需要良好的统计属性,却不关心可预测性(Monte-Carlo模拟,单人扑克与计算机,一般来说是计算机游戏)–即无法赢得金钱或生命如果有人能够成功地预测那些随机数,就迷路了。
  • 关于java - SecureRandom的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11099241/

    10-10 06:34