【问题标题】:How to generate a 384-bit Symmetric Key Size in Java?如何在 Java 中生成 384 位对称密钥大小?
【发布时间】:2019-07-15 14:04:53
【问题描述】:

我正在研究一种密码,它采用比 256 位(即 384 位)更大的对称密钥大小?有没有一种方法可以使用 384 位的 KDF(或其他任何东西)之类的东西生成对称密钥。我尝试在 java 中使用Key Generator 并使用keyGenerator.init(384),但它最多只支持 256 位。您认为我可以将 128 位对称密钥与 Java 中的密钥生成器生成的 256 位对称密钥结合起来吗?我想避免不得不尝试使用散列函数,对其进行大量迭代,并尝试向其中添加我自己的随机盐。我知道这是一个不常见的问题,因为没有人会寻找 384 位对称密钥大小。我不是特别在寻找 KDF,只是一种生成随机对称密钥的简单而强大的方法。我的用例不涉及获取诸如用户密码之类的低熵信息并将其设为密钥。

【问题讨论】:

  • KeyGenerators 是特定于算法的:如果您的算法在已注册的 Provider 中不受支持,则使用 KeyGenerator 没有多大意义。确实,整个 JCA 都是基于提供程序架构的,如果您的自制密码类无法使用 Key 做任何事情,那么创建 java.security.Key 的实例对您没有多大好处。

标签: java encryption cryptography aes encryption-symmetric


【解决方案1】:

您认为我可以将 128 位对称密钥与 Java 中的密钥生成器生成的 256 位对称密钥结合起来吗?

当然,您只需使用 getEncoded() 检索 256 位和 128 位密钥的字节,使用 Arrays.concat 将返回的两个 byte[] 合并为一个 byte[],然后在结果上使用 new SecretKeySpec

我想避免不得不尝试使用散列函数,对其进行大量迭代,并尝试向其中添加我自己的随机盐。

如果您有 256 位源素材,那么您可以使用 HMAC,源素材作为键,任何信息(甚至是空消息)作为 HMAC 输入。如果您使用 SHA-384(如前所述),那么输出将是一个整洁的 384 位密钥材料,可用作SecretKeySpec 的输入。

是的,使用带有 SHA-384 的 PBKDF2,静态或什至空的盐和单次迭代(迭代计数为 1)也可以工作。但这在the other answer by Saptarshi 中已经提到。

我知道这是一个不常见的问题,因为没有人会寻找 384 位对称密钥大小。

嗯,有一种 SIV 操作模式,它欺骗并使用一个真正由两个连续键组成的键。所以即使是对称密码也有先例。

如果块或流密码直接使用 256 位密钥,那么我可能会称其为蛇油,因为即使量子计算成为现实,超过 256 位也是没有意义的。


最后,对称密码的密钥只是(伪)随机位 - 包含奇偶校验位的 DES 密钥是奇数位。因此,如果密码与 JCA 不兼容 - 即您真的不需要 SecretKey 对象实例 - 您可以生成一个 48 字节数组,用 SecureRandom 字节填充它并完成。

【讨论】:

  • 为什么只需要 1 次迭代?我认为几次迭代会更好地加强密钥。看来我误解了,并没有真正理解“熵”的概念。我不需要任何用户输入,例如创建密钥的密码。我只需要一个用于 AES 等对称加密算法的随机密钥。使用Secure Random 生成密钥比使用 PBKDF 具有更高的熵。我现在明白,提供密码是为了在必要时使用,比如创建用户密码。从我的用例来看,我认为生成一个随机的 48 字节数组会更有意义。
  • 如果您能澄清空盐和迭代计数 1 的原因,那就太好了。我认为迭代应该是数千次,具体取决于系统功率,而且盐必须是随机的以确保安全。这不是 PBKDF2 所说的吗?或者在这个特定问题的上下文中不需要它?
  • 正是这样,您将使用基于密码的密钥派生函数作为 基于密钥的 密钥派生函数,并且不需要迭代计数。随机盐可能会加强它,但仍应视为可选。
【解决方案2】:

为什么不使用SecretKeyFactory 类和PBKDF2WithHmacSHA384 算法。您可以在文档 herehere 中找到详细信息。

代码如下所示:

SecureRandom random = SecureRandom.getInstanceStrong();
byte[] salt = new byte[32];
random.nextBytes(salt);
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, 
   keyLength);
SecretKeyFactory keyFactory = 
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA384");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
    "AES");

最好在使用后清除SecretKeySpecSecretKey 以避免通过堆转储暴露密钥。从 Java 8 开始,没有简单的方法可以做到这一点,因为这两个接口的实现似乎没有实现接口 Destroyable 的方法 destroy()。所以使用后使用反射来清除它们。

【讨论】:

  • 没有理由使用特定的哈希函数,PBKDF2 能够使用任何常见的安全 Hmac 生成 384 位的密钥材料。
  • @James K Polk 这样做会不会更好:SecretKeyFactory.getInstance("PBKDF2WithHmac").
  • 我不明白为什么会更好。 PBKDF2 用于从 password 或类似的低熵源生成密钥位。如果您只想要一个随机的 384 位密钥,请使用 byte [] key = new byte[384 / 8]; new SecureRandom().nextBytes(key);
  • @JamesKPolk 我会在不眨眼的情况下使用 PBKDF2,但我会确保我的char[] 只会在最低有效位中包含字节值,当然要确保char[] 和之前的 byte[] 可能会在使用后被销毁。 Saptarshi,您会特意销毁密钥,但当然,在这种情况下也需要销毁源材料。您还生成了一个强随机盐(为什么?)并且您没有指定迭代计数(具有值 1)。
  • 当然没问题。但是,我建议您不要在问题的标题中添加这样的答案建议,如果您将它放在问题中的话。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2014-02-21
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-29
  • 2012-11-30
相关资源
最近更新 更多