AES 256解密-IV共享安全吗



根据这个问题及其答案,我正在创建一个应用程序,该应用程序给定密码字符串,将转换明文并将其密文、生成的salt和初始化向量存储在文本文件中。

在以下代码中:

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个参数(密文、salt、iv:字节数组)。

存储初始化向量是否安全?

这个问题的答案清楚地表明,盐不需要是秘密的,显然密文也可以使用,但iv参数呢?

编辑如果共享不安全,是否可以单独从盐中检索原始iv?

是的,IV可以是公共信息。您可以将计算用作IV,只要您从不使用键和IV的组合两次即可。换句话说,只要您为每个加密更改salt,您就应该能够仅共享salt。

此外,对于CBC;看起来像是随机的";对攻击者而言,尤其是在用于同一密钥时。因此,通常的方案是使用PBKDF2的一些输出作为IV数据。当然,这些特定的位也不应该用于创建密钥,但可以分割输出大小。

这有一些缺点,因为如果您请求超过160位的信息(对于SHA1),PBKDF2将使用更多的轮次。因此,您可以将PBKDF2的输出和计数器(密钥为0,IV为1)连接起来,并使用例如SHA256生成128位密钥(最左边的16个字节)和128位IV(最右边的16个)。


让我们探索一下这个方案的一些变体:

  • 您也可以使用不同的散列(如SHA-512)来创建更大的输出,并对其进行拆分以获得密钥和IV,但请注意,这样的函数可能不适用于所有地方。Java 8应该有"PBKDF2WithHmacSHA512"(对于SecretKeyFactory)。

  • 您也可以生成一个PBKDF2输出,然后使用HKDF或HKDF Expand来导出密钥和IV。问题是,HKDF/HKDF Expand不能直接从Java获得。BouncyCastle确实有这个方法,因为我发送了各种KDF的实现。

  • 还有一种方法是使用SecureRandom生成新的IV,但在这种情况下,您需要同时存储salt和IV。如果您需要使用同一密钥加密多个消息,这可能会很有用。在这种情况下,您可以为每个单独的消息生成并存储一个IV。如果您能够简单地存储16个额外的字节,那么这是一个很好的方法。

  • 原则上,您也可以使用全零IV,只要您从不重复使用同一密钥(即,从不重复使用相同的密码/盐组合)。但是,在这种情况下,您可能希望使用AES-256来避免多目标攻击。

最新更新