【问题标题】:Java AES in CBC and CFB modes not encrypting properly? IV not respected?CBC 和 CFB 模式下的 Java AES 未正确加密?四不尊重?
【发布时间】:2019-11-25 18:00:41
【问题描述】:

我一直在使用基本的 Java AES 东西进行一些学习/实验,但我不知道我做错了什么。根据文档, doFinal() 应该一次性加密/解密所有内容,而且它似乎确实这样做了;但是,在解密时,使用无效的 IV,我仍然可以解密 大部分 数据。为了安全起见,请告诉我我的测试代码到底哪里搞砸了?

注意:我没有使用 BC 或 Java Unlimited Strength Crypto Extensions。此代码遵循来自The Oracle JCA Reference Guide 的示例和指导。在下面的代码中,我选择带有 CFB 的 AES(与 CBC 的结果相同),生成密钥,生成 IV,输入 encrypt,核对 IV,然后输入 decrypt,理想情况下(如果我正确理解 CBC 和 CFB),nuked IV 应该将解密的输出渲染为垃圾。但它没有……至少,在我的安装中没有……

还应注意 GCM 确实可以正常工作(您无疑会看到下面注释掉的算法字符串),但 CBC 和 CFB 的这种行为让我感到困扰。现实检查一下好吗?

    public static void encdec() throws Exception {
        // let's encrypt something!
        String message = "This is a super-secret message.  Don't read this message.  This message will self-destruct...";

        final String symmetricCipherSpec = "AES/CFB/PKCS5Padding";// "AES/GCM/NoPadding";
        final String symmetricKeySpec = "AES";

        System.out.println("\n\nSelecting plaintext cypher...");
        Cipher cipher = Cipher.getInstance(symmetricCipherSpec);

        // What did we get?
        System.out.println("--> Cipher Algorithm Selected: " + cipher.getAlgorithm());
        AlgorithmParameters parameters = cipher.getParameters();
        System.out.println("--> Parameters for algo:       " + parameters.getAlgorithm());
        System.out.println("--> block size:                " + cipher.getBlockSize());
        final int blockSize = cipher.getBlockSize();

        KeyGenerator keyGenerator = KeyGenerator.getInstance(symmetricKeySpec);
        keyGenerator.init(128);
        Key key = keyGenerator.generateKey();
        System.out.println("\nsymmetric key = " + Hex.encodeHexString(key.getEncoded()));

        // set up for encryption
        int tLen = 16;
        byte[] basicIV = new byte[tLen];
        for (int i = 0; i < basicIV.length; i++) {
            basicIV[i] = (byte) i;
        }

        byte[] messageToEncrypt = message.getBytes();
        IvParameterSpec ivSpec = new IvParameterSpec(basicIV);
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        byte[] encryptedMessage = cipher.doFinal(messageToEncrypt);

        System.out.println("\nencrypted     = " + Hex.encodeHexString(encryptedMessage));
        byte[] iv = cipher.getIV();
        System.out.println("iv            = " + Hex.encodeHexString(iv) + " (len=" + iv.length + ")");

        // reset IV to garbage.
        basicIV = new byte[tLen];
        ivSpec = new IvParameterSpec(basicIV);
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] decrypted = cipher.doFinal(encryptedMessage);

        System.out.println("\ndecrypted     = " + new String(decrypted));
        System.out.println("original      = " + message);
        System.out.println("iv            = " + Hex.encodeHexString(cipher.getIV()) + " (len=" + cipher.getIV().length + ")");
    }

【问题讨论】:

标签: java aes jce cbc-mode


【解决方案1】:

没关系...我对 CBC 的理解是有缺陷的;这代码按预期工作。每Wikipedia

使用不正确的 IV 解密会导致第一个明文块损坏,但随后的明文块将是正确的。这是因为每个块都与前一个块的密文而不是明文进行异或运算,因此不需要先解密前一个块,然后将其用作IV来解密当前块。

【讨论】:

  • 顺便说一句,关于您的 // reset IV to garbage 评论 - 您可能已经知道这一点,但 Java 会将您的字节数组初始化为全 0,因此不太垃圾/
  • 是的,我确实知道 :) 无论如何,它是一个不同于原版的 IV,所以有人可以说我的评论是“有希望的”,与我预期的结果输出一样!
猜你喜欢
  • 1970-01-01
  • 2012-06-17
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2022-11-16
  • 2019-04-07
  • 1970-01-01
  • 2015-06-18
相关资源
最近更新 更多