Java 1.8 版能否生成与 Java 1.6 版相同的 SecureRandom 值?

Can Java version 1.8 generate the same SecureRandom Value as Java version 1.6?

我在系统验证系统上遇到问题。 我们的服务器使用的是1.6版本,客户端使用的是1.8版本,在认证的过程中,我们通过"SHA1PRNG"SecureRandom生成一个key,代码如下: 即:

KeyGenerator keygen = KeyGenerator.getInstance("Blowfish"); 
SecureRandom foo = SecureRandom.getInstance("SHA1PRNG");
foo.setSeed("baa".getBytes());
keygen.init(foo);

问题是,我们发现客户端生成的密钥与服务器生成的密钥不同。累的把所有步骤都打印出来,发现问题出在SecureRandom,即foo.setSeed("baa".getBytes());之后如果再调用foo.nextBytes(),会给出不同的值[=21] =]

因此,我们想知道有没有办法让双方产生相同的价值? (鉴于无法更改客户端和服务器中 Java 的版本。)或者 Java 中是否有任何平台无关的 SecureRandom 方法?

背景信息:Unix 中的 SERVER 和 CLIENT 运行。 我有一个桌面 运行ning Java 1.8,我测试了以下内容:

  1. Desktop Java1.8可以加解密CLIENT中生成的密钥(Java1.8)

  2. CLIENT (Java 1.8) 无法加密或解密SERVER (Java 1.6) 中生成的密钥,反之亦然。

  3. CLIENT已安装Java1.6(仅供测试)无法加密或解密SERVER(Java1.6)中生成的密钥。我们猜测这是因为 /dev/random/dev/urandom 已被覆盖为 Java 1.8 版本。因此,即使 Java 的版本相同,它们也有不同的行为。

来自 the documentation for SecureRandom:

Additionally, SecureRandom must produce non-deterministic output. Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in RFC 1750: Randomness Recommendations for Security.

因此,您不仅通过传递可预测的种子违反了 SecureRandom 的要求,而且明确要求 SecureRandom 的输出是 不可预测的.

为了生成可预测的随机序列,使用Random:

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.

但要注意:如果你每次都使用相同的种子,那么数字总是相同的,所以你必须使用相同的初始种子,即以某种方式在客户端和服务器之间共享。每次重新启动服务器应用程序时都需要重置此初始种子。

Random 的实例必须在对例程的调用之间共享,否则每次都会生成相同的单个数字:

public static void main(final String[] args) {
    IntStream.range(1, 10)
            .map(i -> new Random(42).nextInt())
            .forEach(System.out::println);
}

输出:

-1170105035
-1170105035
-1170105035
-1170105035
-1170105035
-1170105035
-1170105035
-1170105035
-1170105035

一般来说,您要做的是 Bad Idea TM。使用 an asymmertric encryption scheme 而不是尝试自己重新发明轮子会更好。

不要发明自己的键偏差函数。使用为此发明的功能。

您不会写下您用作密钥偏差输入的内容,但如果它是密码,您可以使用 PBE(基于密码的加密)密钥规范 - 如下所示:

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "Blowfish");