为什么我得到 javax.crypto.BadPaddingException (AES/CBC/PKCS5Padding)

Why am I getting javax.crypto.BadPaddingException (AES/CBC/PKCS5Padding)

我正在尝试使用 AES/CBC/PKCS5Padding 让一些 encryption/decryption 继续运行,但得到了一个奇怪的结果。根据我用来加密的原始值,我得到一个异常:

javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

为了对此进行测试,我编写了一个小函数,它以字符串开头并逐渐变大,尝试在每次迭代中加密字符串并解密加密结果。

如果始终无法解密项目 0 和 4(第​​一个和最后一个)中的加密值。它成功解密了其他值。

任何可能导致此问题的线索?

这是程序的输出:

0 **************************************

ENCRYPT Key: [00000000000000000000000000000000] value: [5]
This is the ciphertext encrypted [ÂZ??¢?»NÔå?Ó^Ç ]
Encrypted Value = [C25A863FA23FBB4ED4E53FD35E7FC7A0]
DECRYPT Key: [00000000000000000000000000000000] value: [C25A863FA23FBB4ED4E53FD35E7FC7A0]
This is the ciphertext [[B@5fdef03a]
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
        at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:977)
        at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1058)
        at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855)
        at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
        at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
        at com.mgl.siebel.crypt.AES256Crypt.decrypt(AES256Crypt.java:35)
        at com.mgl.siebel.crypt.AES256Crypt.test2(AES256Crypt.java:85)
        at com.mgl.siebel.crypt.AES256Crypt.main(AES256Crypt.java:101)
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

1 **************************************

ENCRYPT Key: [00000000000000000000000000000000] value: [55]
This is the ciphertext encrypted []­*çü×z%?eÑ¥zx~÷]
Encrypted Value = [5DAD2AE7FCD77A259665D1A57A787EF7]
DECRYPT Key: [00000000000000000000000000000000] value: [5DAD2AE7FCD77A259665D1A57A787EF7]
This is the ciphertext [[B@5ccd43c2]
Decrypted Value = [55]

2 **************************************

ENCRYPT Key: [00000000000000000000000000000000] value: [555]
This is the ciphertext encrypted [M÷o?gI¶àeØÖ8c.+]
Encrypted Value = [4DF76F916749B6E065D807D638632E2B]
DECRYPT Key: [00000000000000000000000000000000] value: [4DF76F916749B6E065D807D638632E2B]
This is the ciphertext [[B@4aa8f0b4]
Decrypted Value = [555]

3 **************************************

ENCRYPT Key: [00000000000000000000000000000000] value: [5555]
This is the ciphertext encrypted [ÖFè7tÔ·ðGÂ?WÂGs ]
Encrypted Value = [D646E83774D4B7F047C28657C24773A0]
DECRYPT Key: [00000000000000000000000000000000] value: [D646E83774D4B7F047C28657C24773A0]
This is the ciphertext [[B@7960847b]
Decrypted Value = [5555]

4 **************************************

ENCRYPT Key: [00000000000000000000000000000000] value: [55555]
This is the ciphertext encrypted [ȱiã?'èÀ­0<eäy?]
Encrypted Value = [C80EB169E33F27E8C0AD303C65E4791B]
DECRYPT Key: [00000000000000000000000000000000] value: [C80EB169E33F27E8C0AD303C65E4791B]
This is the ciphertext [[B@2aae9190]
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
        at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:977)
        at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1058)
        at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855)
        at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
        at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
        at com.mgl.siebel.crypt.AES256Crypt.decrypt(AES256Crypt.java:35)
        at com.mgl.siebel.crypt.AES256Crypt.test2(AES256Crypt.java:85)
        at com.mgl.siebel.crypt.AES256Crypt.main(AES256Crypt.java:101)
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

这是正在执行的代码


  public String decrypt(String key, String encryptedRawValue) throws Exception {
        System.out.println("DECRYPT Key: [" + key + "] value: [" + encryptedRawValue + "]");
        try {
          if ((key == null) || (encryptedRawValue == null)) {
            throw new Exception("key and value must not be null");
          } 
          
          // convert raw value into its original encrypted sequence of bytes
          byte[] ciphertext = DatatypeConverter.parseHexBinary(encryptedRawValue);
          System.out.println("This is the ciphertext [" + ciphertext + "]");
          byte[] raw = key.getBytes(Charset.forName("UTF-8"));
          if (raw.length != 32) {
            throw new IllegalArgumentException("Invalid key size.");
          }
          SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
          
          Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
          cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
          byte[] original = cipher.doFinal(ciphertext);
          String plainTextValue = new String(original, Charset.forName("UTF-8"));
          return (plainTextValue);
        } catch (Exception e) {
          e.printStackTrace();
          throw e;
        }
      }
      
  public String encrypt(String key, String value) throws Exception {
        System.out.println("ENCRYPT Key: [" + key + "] value: [" + value + "]");
    try {
      byte[] raw = key.getBytes(Charset.forName("UTF-8"));
      if (raw.length != 32) {
        throw new Exception("Invalid key size.");
      }
  
      SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
      String encryptedValue = new String(cipher.doFinal(value.getBytes(Charset.forName("UTF-8"))));
      System.out.println("This is the ciphertext encrypted [" + encryptedValue + "]");

      String rawValue = DatatypeConverter.printHexBinary(encryptedValue.getBytes());
      return (rawValue);
    } catch(Exception e) {
      e.printStackTrace();
      throw e;
    }
  }


  private void test2() throws Exception {
    String key = "00000000000000000000000000000000";
    try {
      String value = "";
      for (int i=0; i < 5; i++) { // loop 5 times encrypting and decrypting 
        System.out.println("\n" + i + " **************************************\n");
        try {
          value = value + "5";
          String encryptedValue = this.encrypt(key, value);
          System.out.println("Encrypted Value = ["+ encryptedValue + "]");
    
          String plainTextValue = this.decrypt(key, encryptedValue);
          System.out.println("Decrypted Value = ["+ plainTextValue + "]");

        } catch(Exception e) {
          System.out.println(e.getMessage());
        }

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

  public static void main(String[] args) {
    AES256Crypt c = new AES256Crypt();
    try {
      c.test2();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }


}

String encryptedRawValue

这行不通。字符串是 个字符 的序列。加密数据是 字节 的序列。如果我们生活在神奇的独角兽王国,在那里 unicode 和更普遍的西方字符可以被视为不存在而被挥手而去,那么您可以编写非常糟糕的代码并将两者混为一谈。这在古代很常见。 所以 不好,这是 python 2 决定放弃一切并搬到 python 3.

的主要原因

只有一个修复。停止这样做。正确的类型是 byte[]。如果您出于某种原因需要以字符串形式呈现此 byte[],那么唯一合理的原因是因为它需要在高度受限的场所呈现,例如电子邮件。在这种情况下,您应该对其进行 base64 编码。如果需要,请在网上搜索 'java base64' 以了解如何执行此操作。这些 API 是正确的:'encode' 方法接受一个 byte[] 和 returns 一个字符串,decode 方法接受一个字符串和 returns 一个字节[]。

解决这个问题,问题就会消失。

String encryptedValue = new String(cipher.doFinal(value.getBytes(Charset.forName("UTF-8"))));

不要将 doFinal 的结果包装到 new String 中。取字节数组。那是你的数据。