【问题标题】:Does AES/CBC really require IV parameter?AES/CBC 真的需要 IV 参数吗?
【发布时间】:2014-01-20 05:59:08
【问题描述】:

我正在编写一个简单的应用程序来使用 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();
        }

    }
}

【问题讨论】:

  • 之所以有效,是因为 Java 选择了一个随机 IV。您可以在初始化后使用enCipher.getIV() 来查看值(并将它们发送到另一端)。
  • doridori.github.io/Android-Security-Beware-of-the-default-IV 当您使用 AES/CBC/PKCS5Padding 时,它可能使用的是旧的 AndroidOpenSSL 实现,(遗憾的是)默认为 [0] IV

标签: java aes password-encryption cbc-mode


【解决方案1】:

当它在没有 IV 的情况下使用时,对于包括 AES 在内的某些类型的密码,它隐式使用 0 IV。请参阅密码类documentation

null IV(或确定性 IV)的缺点是容易受到字典攻击。 IV的要求是防止同一个明文块每次都产生同一个密文。

【讨论】:

  • 实际上,如果您没有指定,Java SE 会使用随机 IV。您的链接指向 Java 卡 API。如果你不指定一个,你会得到一个随机的,如果你没有设置它,你需要用cipher.getIV()检索它。
【解决方案2】:

正如其他用户所说,这取决于 JCE 提供者。如果您不指定,Java SE 会为您生成一个随机 IV。

只有 Android1 和 Javacard API 使用空白 IV,这不符合 Java Crypto 规范 which states

如果此密码需要任何无法从给定 key 派生的算法参数,则底层密码实现应该生成本身所需的参数(使用特定于提供程序的默认值或随机值)如果它正在为加密或密钥打包而初始化,如果它正在为解密或密钥解包而初始化,则引发InvalidKeyException。可以使用getParametersgetIV 检索生成的参数(如果参数是IV)。

如果你没有指定 IV,在 Java SE 中你会得到一个随机的,并且需要使用 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 广告一样。只是猜测,仅此而已。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    • 2011-07-03
    • 2022-12-16
    • 1970-01-01
    相关资源
    最近更新 更多