【问题标题】:Reusing PBKDF2 salt for AES/GCM as IV: dangerous?为 AES/GCM 重复使用 PBKDF2 盐作为 IV:危险吗?
【发布时间】:2018-07-20 10:51:33
【问题描述】:

我正在开发一个加密实用程序类,可重复用于常见操作。

一种非常常见的情况是使用用户提供的密码加密明文。
在这种情况下,我使用 PBKDF2 导出有效的 AES 密钥,然后在 GCM 模式下使用它来加密明文。

一些代码:

// IV_LEN = 96
// ITERATIONS = 1000 ~ 4000
// KEY_LEN = 128 ~ 256
// TAG_LEN = 128
public static String encrypt(byte[] plain, char[] password) throws GeneralSecurityException
{
    SecureRandom rng = SecureRandom.getInstanceStrong();
    byte[] iv = new byte[IV_LEN / 8];
    rng.nextBytes(iv);

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    SecretKey derivedKey = factory.generateSecret(new PBEKeySpec(password, iv, ITERATIONS, KEY_LEN));
    SecretKey secretKey = new SecretKeySpec(derivedKey.getEncoded(), "AES");

    Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
    c.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LEN, iv));

    byte[] encrypted = c.doFinal(plain);

    Encoder encoder = Base64.getUrlEncoder().withoutPadding();

    return encoder.encodeToString(iv) + ":" + encoder.encodeToString(encrypted);
}

目前,我也在使用 PBKDF2 salt(96 位 - SecureRandom)作为 AES/GCM 加密的 IV。

salt 和 IV 都可以公开,但不应重复使用。

是否应该理解它们不应该在同一个功能/服务/算法中重复使用,或者它们不应该在任何地方重复使用?

修改这个方法很容易生成不同的盐和IV,但是有这样做的理由吗?

谢谢

【问题讨论】:

  • 有什么理由这样做吗?
  • @erickson 实际上,不 - 这只是病态的好奇心......并且返回的记录要短一些字节! :)
  • @erickson CMS (PKCS #7) 的问题,大概是RFC 5084,是 RFC 不够友好,使用了ASN.1。您有更好的面向用户的参考和示例吗?如果没有更好的信息,吸收率将会很低。
  • @James“我认为你应该写”好吧,我没有这样做的经验或证书,会是一个更好的候选人。 ??????
  • @JamesKPolk 也许类似下面的内容可能会从 RFC 5084 等中提取一些概念:{ algorithm:{ name: mode: key_size: block_size: } mode: { name initializer } padding: { name: } key_derivation: { name: key: count: } authentication: { hash_name: key_method: } Additional: { user defined key/value fields } } data 但这对于仅加密一两个块是不实用的。现在轮到你了。

标签: java encryption cryptography pbkdf2 aes-gcm


【解决方案1】:

请注意,您可能不需要重新生成随机 IV,只要您更改盐和生成的密钥。如果您每次(重新)加密时都不更改盐,那么您确实需要单独的 IV,否则您可能会将信息泄露给对手。

您可以保持盐和 IV 相同。但通常更容易从密码和盐中导出 IV 以及密钥。如果您将 PBKDF2 与 SHA-512 散列一起使用,这很容易:只需从生成的散列中取出 128、192 或 256 位 AES 密钥,然后再取另外 128 位作为 IV 并使用它。

如果您需要多个密钥或者如果您使用较小的散列,那么您可能需要从 PBKDF2 的结果中派生更多的密钥。在这种情况下,最好将 PBKDF2 的结果标记为主密钥,并从中执行 N 个密钥派生,每个密钥一个,IV 一个。你可以使用例如HKDF 为此,Bouncy Castle 有一个实现(为此我提供了初始源代码)。

【讨论】:

  • 所以应该是安全的。实际上,此方法使用一次性 salt/iv 和仅一个派生的 aes-key 来加密小消息。这些都不能重用/可重用,因为 salt/iv 是随机生成的,而 aes-key 是从 random-salt/iv 派生的。感谢您的建议:我没想到我可以将部分派生密钥用作aes-key,部分用作IV,它既简单又聪明。另外我会记住多键情况下的 HKDF 从键。谢谢
猜你喜欢
  • 2014-05-12
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 2018-10-17
  • 2016-11-14
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多