我的手上有一个窘境。我创建了一个AES服务来加密/解密敏感信息。 AES密钥是使用java SecureRandom
随机生成的。我有一个存储种子的受保护文件,在调用服务时,种子被填充到安全随机类中。
为了确保它有效,我有以下逻辑:
private boolean secureRandom(final String seed) {
SecureRandom sr1 = new SecureRandom(seed.getBytes(UTF8_CHARSET));
SecureRandom sr2 = new SecureRandom(seed.getBytes(UTF8_CHARSET));
//Two secure random with the same seed should generate the same results
boolean secureRandomWorks = sr1.nextLong() == sr2.nextLong();
if (!secureRandomWorks) {
System.err.println("Secure random not supported. Defaulting to old key");
}
return secureRandomWorks;
}
这里的想法是我应该能够使用相同的种子创建两个安全的随机对象,并且在调用nextLong()
时应该返回相同的值
当我在Windows机器上部署我的应用程序时,这很好用,但是当我在RHEL 7机器上部署它时,我得到了我的错误。
我的印象是,只要种子相同,两个实例将始终产生相同的输出。这似乎是在Windows上的情况,但是当我在RHEL 7上测试它时,情况似乎并非如此。
我创建了这个简单的测试以查看验证:
SecureRandom sr1 = new SecureRandom("encryptionKey".getBytes("UTF-8"));
SecureRandom sr2 = new SecureRandom("encryptionKey".getBytes("UTF-8"));
for (int i = 0; i < 1000; i++) {
System.out.println(sr1.nextLong() == sr2.nextLong());
}
在Windows上,每个输出都是真的,而在RHEL 7上这是错误的。
关于什么可能导致RHEL 7忽略种子的任何想法?
答案 0 :(得分:3)
我找不到任何禁止您在RHEL 7上观察到的行为的文档。
java.util.Random
的JavaDoc明确说明
如果使用相同的种子创建了两个Random实例,并且为每个实例创建了相同的方法调用序列,则它们将生成并返回相同的数字序列
java.security.SecureRandom
的JavaDoc不包含类似的声明。
相反,它提到(在setSeed()
方法的文档中)
重新种植此随机对象。给定的种子补充而不是替代现有的种子。因此,保证重复呼叫永远不会减少随机性。
答案 1 :(得分:0)
事实证明,RHEL 7(以及一般的Linux机器)默认使用与Windows不同的算法。 Linux使用NativePRNG
,而Windows使用SHA1PRNG
。
Linux使用内置/dev/random
或/dev/urandom
并使用NativePRNG
。
考虑到这一点,我能够改变初始化SecureRandom对象的方式
private static final String ALGORITHM = "SHA1PRNG";
private static final String PROVIDER = "SUN";
private SecureRandom getSecureRandom(String seed) throws NoSuchAlgorithmException, NoSuchProviderException {
SecureRandom sr = SecureRandom.getInstance(ALGORITHM, PROVIDER);
sr.setSeed(seed.getBytes(UTF8_CHARSET));
return sr;
}
从文档中getInstance
不会为对象播种,因此它可以根据需要进行播种。
返回的SecureRandom对象尚未播种。播种 返回对象,调用setSeed方法。如果没有调用setSeed, 第一次调用nextBytes将强制SecureRandom对象播种 本身。如果先前使用setSeed,则不会发生这种自播种 调用。
现在它被迫使用我需要的东西,我不应该对RHEL 7有任何问题。