java - 在 java11 上播种后,SHA1PRNG SecureRandom 行为有所不同

标签 java security random cryptography sha

我使用 java.security.SecureRandom"SHA1PRNG" 算法来生成加密 key 。这是用于加密不太重要的数据的历史代码。然而,当我们从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=-4273821888324981770k2=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

任何帮助将不胜感激。

最佳答案

[免责声明]: 不要这样做(除非您想要向后兼容)。如果你想要可预测性,你应该基于可靠的 RNG 来实现你的解决方案,我也是如此。但不幸的是,我们必须支持旧文件版本的格式,而且这些文件不包含任何敏感或个人数据,但我们不希望用户更改这些数据,因为这些数据以类似文本的格式存储,因此很容易被更改。

我没有实现我自己的“SHA1PRNG”,因为它太难了(在评论中提到)。相反,我破解了较新的 PRNG 版本,使其行为与旧版本完全相同。原因是,自 java9 OpenJDK 创建者决定制作新版本的 secureRandomSpi 来每次 SecureRandom 重置 remCount 整数字段的值。 setSeed()被调用,旧版本没有。

如果你想实现这个 hack,你要做的第一件事是通过调用 "SUN".equals(secureRandom.getProvider().getName()) && "SHA1PRNG".equals(secureRandom.getAlgorithm()); 来检查 SecureRandom 实例是否真正是 SUN 的“SHA1PRNG”,然后通过反射获取它的 SPI 并保存其值remCount 字段。然后您可以调用 setSeed() 并将保存的值安装回 remCount 字段。我不想在这里发布这段晦涩的代码,但你已经明白了。谢谢。

关于java - 在 java11 上播种后,SHA1PRNG SecureRandom 行为有所不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57142890/

相关文章:

java - 在 google app engine for java 中使用 xml rpc 客户端 - 超时时间为 30 秒? - 如何使用低级 API 进行访问

security - 第三方是否可以可靠地识别您的 CMS?

web-services - 编写安全的 REST Web 服务

opengl - 每个 OpenGL/GLUT 循环迭代的新 StdGen

java - 随机生成方程的算法

java - java中从HTTP响应中解析并获取特定字段

java - 如何使用java删除重复单词

Java递归方法将参数的数字相加

c# - .net C#,保护每种方法的最佳实践是什么?

Python - 无重复数字的 5 位随机数生成器