为什么我会得到javax.crypto.badpaddingexception(aes/cbc/pkcs5padding)

um6iljoc  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(774)

我正在尝试使用aes/cbc/pkcs5padding进行一些加密/解密,得到了一个奇怪的结果。根据我用来加密的原始值,我得到一个异常: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption. 为了测试这一点,我编写了一个小函数,它从一个字符串开始,并逐步使它变大,尝试加密字符串,并在每次迭代中解密加密的结果。
第一次迭代==>字符串==“5” Encrypt and decrypt 下一次迭代==>字符串==“55” Encrypt and decrypt 下一次迭代==>字符串==“555” Encrypt and decrypt 下一次迭代==>字符串==“5555” Encrypt and decrypt 下一次迭代==>字符串==“55555” Encrypt and decrypt 如果始终未能解密第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();
    }
  }

}
liwlm1x9

liwlm1x91#

String encryptedRawValue 这行不通。字符串是一个字符序列。加密数据是字节序列。如果我们生活在神奇的独角兽世界里,unicode和更普遍的西文字符可以被当作不存在而挥霍掉,那么你就可以编写非常糟糕的代码并将两者混为一谈。这在古代很常见。这太糟糕了,这是python2决定放弃它并迁移到python3的一个主要原因。
只有一个办法。别这样。正确的类型是 byte[] . 如果出于某种原因需要以字符串形式呈现这个byte[],那么唯一合理的原因是需要在高度受限的场所(例如电子邮件)中呈现它。在这种情况下,应该对其进行base64编码。如果必须的话,可以在网上搜索“javabase64”来了解如何做到这一点。这些api做得很好:“encode”方法接受一个byte[]并返回一个字符串,“decode”方法接受一个字符串并返回一个byte[]。
解决这个问题,问题就会消失。 String encryptedValue = new String(cipher.doFinal(value.getBytes(Charset.forName("UTF-8")))); 不要 Package 结果 doFinal 进入 new String . 以字节数组为例。这是你的数据。

相关问题