Java 将PBKDF2盐重新用于AES/GCM as IV:危险?

Java 将PBKDF2盐重新用于AES/GCM as IV:危险?,java,encryption,cryptography,pbkdf2,aes-gcm,Java,Encryption,Cryptography,Pbkdf2,Aes Gcm,我正在开发一个加密实用程序类,可用于普通操作 一种非常常见的情况是使用用户提供的密码加密明文。 在本例中,我使用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 G

我正在开发一个加密实用程序类,可用于普通操作

一种非常常见的情况是使用用户提供的密码加密明文。
在本例中,我使用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

盐和IV都可以公开使用,但不能重复使用

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

修改此方法以生成不同的盐和IV非常容易,但有理由这样做吗


谢谢

请注意,只要您更改了salt,从而更改了生成的密钥,您可能不需要重新生成随机IV。如果每次(重新)加密时不更换salt,则需要单独的IV,否则可能会将信息泄漏给对手

你可以保持盐和静脉注射相同。但通常更容易从密码和salt中导出IV和密钥。如果将PBKDF2与SHA-512散列一起使用,这很容易:只需从结果散列中获取128、192或256位AES密钥,然后再获取另一个128位后续位作为IV并使用它


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

有什么理由不这么做吗?@erickson事实上,没有-这只是病态的好奇心。。。并且返回的记录短了一些字节!:)@erickson CMS(PKCS#7)的问题大概是RFC不够友好,使用起来也不方便。您是否有更好的面向用户的参考资料和示例?如果没有更好的信息,理解率就会很低。@James“我认为你应该写”好吧,我没有这样做的经验或资历,你会是一个更好的候选人@JamesKPolk可能类似于以下内容,可能是从RFC 5084和类似内容中提取一些概念:{算法:{name:mode:key\u size:block\u size:}模式:{name initializer}填充:{name:}key\u派生:{name:key:count:}身份验证:{散列\名称:键\方法:}附加:{用户定义的键/值字段}数据,但这对于加密来说很难。现在轮到你了。所以它应该是安全的。实际上,这种方法使用一次性salt/iv和一个派生的aes密钥来加密一条小消息。由于salt/iv是随机生成的,而aes密钥是从random salt/iv派生的,所以这些密钥都不能重用/重用。谢谢你的建议:I没想到我可以使用一部分派生密钥作为aes密钥和一部分作为IV密钥,这既简单又智能。而且我会记住多密钥情况下的HKDF从密钥。谢谢