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



>我在系统身份验证系统上遇到问题。 我们的服务器使用1.6版本,而客户端使用1.8版本,在身份验证过程中,我们通过SecureRandom"SHA1PRNG"生成密钥,同时使用以下代码: 即:

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

问题是,我们发现客户端中生成的密钥与服务器中生成的密钥不同。我们已经厌倦了打印出所有步骤,发现问题是由SecureRandom引起的,即foo.setSeed("baa".getBytes());后如果我们调用foo.nextBytes(),它会给出不同的值。

因此,我们想知道是否有任何方法可以保持双方生成相同的值?(鉴于客户端和服务器中的 Java 版本都无法更改。还是任何独立于平台的 JavaSecureRandom方法?

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

桌面Java 1.8
  1. 可以加密和解密在CLIENT(Java 1.8)中生成的密钥

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

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

来自SecureRandom的文档:

此外,SecureRandom必须产生非确定性输出。 因此,传递给SecureRandom对象的任何种子材料都必须 不可预测,所有SecureRandom输出序列都必须 加密强度,如 RFC 1750:随机性中所述 安全建议。

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

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

如果使用相同的种子创建了两个Random实例,并且 对每个方法调用进行相同的方法调用序列,它们将生成和 返回相同的数字序列。

但请注意:如果每次都使用相同的种子,则数字将始终相同,因此您必须使用相同的初始种子,该种子以某种方式在客户端和服务器之间共享。每次重新启动服务器应用程序时,都需要重置此初始种子。

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

一般来说,您要做的是一个坏主意TM。最好使用非对称加密方案,而不是尝试自己重新发明轮子。

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

您不会编写用作密钥偏差输入的内容,但如果它是密码,则可以使用 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");

相关内容

  • 没有找到相关文章

最新更新