繁体   English   中英

AES 256 解密 - 共享 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM