【发布时间】:2019-07-22 09:22:55
【问题描述】:
我正在使用java.security.SecureRandom 和"SHA1PRNG" 算法来生成加密密钥。这是用于加密次要数据的历史代码。然而,当我们从 java8 切换到 java11 时,我们的代码停止工作。这是重现这种情况的测试用例:
@Test
void srEncryptionSeedTest() throws NoSuchAlgorithmException
{
final long versionSalt = 1850498708034063014L;
final long customSalt = -919666267416765972L;
final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(versionSalt);
final long l1 = sr.nextLong();
final long l2 = sr.nextLong();
sr.setSeed(customSalt);
final long k1 = sr.nextLong();
final long k2 = sr.nextLong();
// check l1 and l2
Assert.assertEquals(l1, 6338935000439666355L);
Assert.assertEquals(l2, -7355545655857008441L);
// Seeding
// check k1 and k2
Assert.assertEquals(k1, -2226559466996804670L); //
Assert.assertEquals(k2, -3123855249705841778L);
}
这在 java11 上运行良好,但在 java8 上我们有 k1=-4273821888324981770 和 k2=3053251164341917236,所以测试失败。如您所见,在产生相同数量的相同随机数后设置完全相同的种子后测试开始失败,所以我怀疑 RNG 的状态不同,但调试对我没有帮助(我无法理解 为什么不一样)。这可以在任何操作系统上轻松复制。
关于 Java8 JVM 的一些事实:
java.vendor -> Oracle Corporation // same goes on OpenJDK builds
java.version -> 1.8.0_202-ea // same goes on 1.8.0_181
java.vm.info -> mixed mode
java.specification.version -> 1.8
java.runtime.name -> Java(TM) SE Runtime Environment
关于 Java11 JVM 的一些事实:
java.vendor -> AdoptOpenJDK
java.version -> 11.0.3
java.vm.info -> mixed mode
java.specification.version -> 11
java.runtime.name -> OpenJDK Runtime Environment
我们将不胜感激。
【问题讨论】:
-
SecureRandom从未声称在运行时生成相同的值。"SHA1PRNG"也没有,因为该算法甚至没有被写下来——它似乎只是代码,并且在 Java SE、其他供应商运行时以及 Java 和 Android 之间存在实现差异。 -
谢谢@MaartenBodewes!我会在 Android 上仔细检查并改进我的问题。额外的问题:Java 中是否有任何可靠的 RNG 可以满足我的要求?
-
我必须检查一下,但this one 似乎是最合适的 - 我会让你寻找它的名字。他们检查测试向量,这些向量应该在种子更新时有结果。因此,在这种情况下,唯一的问题可能是 NIST 调用和 Java API 之间的转换。
-
如果您想生成加密密钥,请使用基于密码的密钥派生函数(如 PBKDF2),或者如果您需要加盐,请使用 HMAC-SHA256 以盐为密钥,但永远不要误用 PRNG!!!
-
谢谢@Robert,我会考虑开发下一个项目,但总的来说这不是我的代码,不幸的是它必须解密一些已经加密的数据(最初的目的是JSON 配置更难修改给用户),所以我现在不能改变方法(我希望我可以,真的)。我想我找到了行为不同的确切原因,我最好仔细检查并回答我自己的问题。
标签: java security random cryptography sha