我正在使用java.security.SecureRandomangorithm"SHA1PRNG"来生成加密密钥。这是用于加密次要数据的历史代码。然而,当我们从java8切换到java11时,我们的代码停止工作。这是重现这种情况的测试用例:@Testvoid 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=-4273821888324981770and k2=3053251164341917236,所以测试失败。如您所见,在生成相同数量的相同随机数后设置完全相同的种子后测试开始失败,所以我怀疑 RNG 的状态不同,但调试对我没有帮助(我不明白为什么这不一样)。这可以很容易地在任何操作系统上重现。关于 Java8 JVM 的一些事实:java.vendor -> Oracle Corporation // same goes on OpenJDK buildsjava.version -> 1.8.0_202-ea // same goes on 1.8.0_181java.vm.info -> mixed modejava.specification.version -> 1.8java.runtime.name -> Java(TM) SE Runtime Environment关于 Java11 JVM 的一些事实:java.vendor -> AdoptOpenJDKjava.version -> 11.0.3java.vm.info -> mixed modejava.specification.version -> 11java.runtime.name -> OpenJDK Runtime Environment任何帮助将不胜感激。
1 回答
哔哔one
TA贡献1854条经验 获得超8个赞
[免责声明]: 不要这样做(除非你想要向后兼容)。如果你想要可预测性,你应该基于可靠的 RNG 实施你的解决方案,我也是。但不幸的是我们必须支持旧文件版本的格式,而且这些文件不包含任何敏感或个人数据,但我们不希望用户更改此数据,因为它以类似文本的格式存储,因此很容易被更改。
我没有实现自己的“SHA1PRNG”,因为它太难了(在评论中提到)。相反,我破解了较新的 PRNG 版本,使其与旧版本完全一样。原因是因为 java9 OpenJDK 的创建者决定在每次调用setSeed()secureRandomSpi
时使新版本重置整数字段的值,而旧版本则没有。remCount
SecureRandom.
如果你想实现这个hack,你要做的第一件事就是SecureRandom
通过调用检查实例是否真的是SUN的“SHA1PRNG” "SUN".equals(secureRandom.getProvider().getName()) && "SHA1PRNG".equals(secureRandom.getAlgorithm());
,然后通过反射获取它的SPI并保存它的remCount
字段值。然后您可以打电话setSeed()
,然后将保存的值安装回现场remCount
。我不想在这里发布这段晦涩难懂的代码,但你已经明白了。谢谢。
添加回答
举报
0/150
提交
取消