[英]javax.crypto.BadPaddingException -Doing Decryption by AES256 with Salt and IV
[英]AES 256 decryption - Is IV safe to share?
在这个问题及其答案之后,我正在创建一个应用程序,该应用程序给出一个密码字符串,将转换明文并将其密文、生成的盐和初始化向量存储在文本文件中。
在以下代码中:
public String decrypt(CryptGroup cp) throws Exception {
String plaintext = null;
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, cp.getSalt(), ITERATIONS, KEY_SIZE);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(cp.getIv()));
plaintext = new String(cipher.doFinal(cp.getCipher()), "UTF-8");
return plaintext;
}
public CryptGroup encrypt(String plainText) throws Exception {
byte[] salt = generateSalt();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_SIZE);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));
return new CryptGroup(ciphertext, salt, iv);
}
CryptGroup 对象包含这 3 个参数(密文、盐、iv:就此而言的字节数组)。
存储初始化向量是否安全?
该问题的答案明确指出,salt 不需要保密,显然密文也可以使用,但是 iv 参数呢?
编辑如果共享不安全,是否可以仅从盐中检索原始 iv?
是的,IV 可以是公共信息。 您可以将计算用作 IV,只要您从不使用 key 和 IV 的组合两次。 换句话说,只要您为每个加密更改盐,您就应该能够只共享盐。
此外,对于 CBC,要求 IV 对攻击者“看起来像随机”,尤其是在用于相同密钥时。 所以通常的方案是使用 PBKDF2 的一些输出作为 IV 数据。 当然,这些特定位也不应该用于创建密钥,但可以拆分输出大小。
这有一些缺点,因为如果您请求超过 160 位的信息(对于 SHA1),PBKDF2 将使用更多的轮次。 因此,您可以将 PBKDF2 的输出和计数器(0 表示密钥,1 表示 IV)连接起来,并使用例如 SHA256 生成 128 位密钥(最左边的 16 个字节)和 128 位 IV(最右边的 16 个字节)。
让我们探索这个方案的一些变体:
您还可以使用不同的散列(例如 SHA-512)来创建更大的输出并将其拆分以获取密钥和 IV,但请注意,此类函数可能并非随处可用。 Java 8 应该有"PBKDF2WithHmacSHA512"
(对于SecretKeyFactory
)。
您还可以生成一个 PBKDF2 输出,然后使用 HKDF 或 HKDF-Expand 来派生密钥和 IV。 问题是 HKDF / HKDF-Expand 不能直接从 Java 获得。 不过,Bouncy Castle 确实有这种方法,因为我发送了各种 KDF 的实现。
另一种方法是使用SecureRandom
生成新的 IV,但在这种情况下,您需要同时存储盐和 IV。 如果您需要使用相同的密钥加密多条消息,这可能很有用。 在这种情况下,您可以为每个单独的消息生成并存储一个 IV。 如果您能够简单地存储 16 个额外的字节,这是一个很好的方法。
原则上,您也可以使用全零 IV,只要您从不重复使用相同的密钥(即从不重复使用相同的密码/盐组合)。 但是,在这种情况下,您可能希望使用 AES-256 来避免多目标攻击。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.