AES/CBC是否真的需要IV参数?

8

我正在编写一款使用AES / CBC(模式)加密我的消息的简单应用程序。根据我的理解,CBC模式需要IV参数,但我不知道为什么我的代码在没有使用IV参数的情况下工作。有人能解释一下吗?谢谢。

输出的加密消息为:T9KdWxVZ5xStaisXn6llfg==,没有异常。

public class TestAES {

    public static void main(String[] args) {

        try {
            byte[] salt = new byte[8];
            new SecureRandom().nextBytes(salt);

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec keySpec = new PBEKeySpec("myPassword".toCharArray(), salt, 100, 128);

            SecretKey tmp = keyFactory.generateSecret(keySpec);
            SecretKeySpec key = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            enCipher.init(Cipher.ENCRYPT_MODE, key);

            // enCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));

            byte[] cipherBytes = enCipher.doFinal("myMessage".getBytes());
            String cipherMsg = BaseEncoding.base64().encode(cipherBytes);

            System.out.println("Encrypted message: " + cipherMsg);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

1
它能够工作是因为Java会选择一个随机的IV。在初始化后,您可以使用enCipher.getIV()来查看这些值(并将它们发送到另一端)。 - eckes
https://doridori.github.io/Android-Security-Beware-of-the-default-IV/ 由于您使用的是 AES/CBC/PKCS5Padding,因此它可能正在使用旧的 AndroidOpenSSL 实现,该实现(可悲的是)默认为 [0] IV。 - Dori
2个回答

10

如果在某些密码类型中(包括AES)没有使用初始化向量(IV),则会隐含地使用0 IV。 请参见Cipher类的文档

空的IV(或确定性IV)的缺点是易受字典攻击。 IV的要求是防止相同的明文块每次产生相同的密文。


3
实际上,如果您没有指定IV,Java SE会使用随机IV。您提供的链接是指Java卡API。如果您没有指定IV,则会得到一个随机的IV,如果您没有设置IV,则需要使用cipher.getIV()来检索它。 - eckes
取决于所使用的“提供程序”,还有https://doridori.github.io/Android-Security-Beware-of-the-default-IV。 - Dori

1
像其他用户所说,这取决于JCE提供程序。如果您未指定任何内容,则Java SE会为您生成随机IV。
只有Android1和Javacard API使用空白IV,这不符合Java加密规范(规范)

如果此密码需要从给定的key中无法派生出任何算法参数,则底层密码实现应在初始化加密或密钥包装时自动生成所需的参数(使用提供程序特定的默认值或随机值),并在初始化解密或密钥解包时引发InvalidKeyException。生成的参数可以使用getParametersgetIV(如果参数是)检索。

如果您未指定IV,在Java SE中,您将获得一个随机的IV,并需要使用cipher.getIV()检索并存储它,因为它将用于解密。

但更好的方法是自己生成一个随机的IV,并通过IvParameterSpec提供它。

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

    SecureRandom rnd = new SecureRandom();
    byte[] iv = new byte[cipher.getBlockSize()];
    rnd.nextBytes(iv);
    IvParameterSpec ivParams = new IvParameterSpec(iv);

    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivParams);

    byte[] ciphertext = cipher.doFinal(input.getBytes());

1 可能是因为Android类似于Java,就像广告中的Eminem-esque一样。只是猜测而已。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接