我正在尝试使用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();
}
}
}
1条答案
按热度按时间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
. 以字节数组为例。这是你的数据。