2

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

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 版本都不能更改。)或者SecureRandomJava 中是否有任何独立于平台的方法?

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

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

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

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

4

2 回答 2

2

文档中SecureRandom

此外,SecureRandom必须产生非确定性的输出。因此,传递给SecureRandom对象的任何种子材料都必须是不可预测的,并且所有SecureRandom输出序列都必须具有加密强度,如RFC 1750: Randomness Recommendations for Security中所述。

因此,您通过传递可预测的种子不仅违反了 的要求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

一般来说,您尝试做的是一个 Bad Idea TM。使用非对称加密方案比尝试自己重新发明轮子要好得多。

于 2018-05-07T08:18:02.213 回答
-1

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

您不会编写用作密钥偏差输入的内容,但如果它是密码,则可以使用 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");
于 2018-05-07T11:30:31.213 回答