即使在阅读了很多有关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在所有测试中都能保证表现良好。
经验法则是在哪里使用
关于java - SecureRandom的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11099241/