RHEL 7 不遵守 java 安全随机种子

RHE 7 Not respecting java Secure Random Seed

我手上有一个难题。我为 encrypt/decrypt 敏感信息创建了 AES 服务。 AES 密钥是使用 java 的 SecureRandom 随机生成的。我有一个存储种子的受保护文件,在调用服务时,种子被填充到安全随机 class.

为了确保它有效,我有以下逻辑:

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()

时它们应该 return 相同的值

当我在 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 忽略种子的任何想法的建议?

我没有找到任何文档禁止您在 RHEL 7 上观察到的行为。

java.util.Random 的 JavaDoc 明确指出

If two instances of Random are created with the same seed, and the same sequence of method calls is made for each, they will generate and return identical sequences of numbers

java.security.SecureRandom 的 JavaDoc 不包含类似的声明。

相反,它提到(在 setSeed() 方法的文档中)

Reseeds this random object. The given seed supplements, rather than replaces, the existing seed. Thus, repeated calls are guaranteed never to reduce randomness.

事实证明,RHEL 7(和 Linux 一般的机器)默认使用与 windows 不同的算法。 Linux 使用 NativePRNG 而 Windows 使用 SHA1PRNG.

Linux 利用内置 /dev/random/dev/urandomNativePRNG.

考虑到这一点,我能够更改初始化 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 没有为对象播种,因此它按照我的需要进行播种。

The returned SecureRandom object has not been seeded. To seed the returned object, call the setSeed method. If setSeed is not called, the first call to nextBytes will force the SecureRandom object to seed itself. This self-seeding will not occur if setSeed was previously called.

现在它被迫使用我需要的东西,我不应该对 RHEL 7 有任何问题。