Java AES字符串解密“给定的最终块未正确填充”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24066679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java AES String decrypting "given final block not properly padded"
提问by pawpaw
For all haters, I READ MANY topics like this one, and non of them was helpful.
对于所有仇恨者,我阅读了很多这样的主题,但没有一个是有帮助的。
eg. here javax.crypto.BadPaddingException: Given final block not properly padded error while decryptionor here Given final block not properly padded
例如。这里javax.crypto.BadPaddingException: 给定最终块在解密时未正确填充错误或此处给定最终块未正确填充
I want to encrypt and then decrypt Strings. Read many topics about "Given final block not properly padded" exception, but non of these solutions worked.
我想加密然后解密字符串。阅读有关“给定最终块未正确填充”异常的许多主题,但这些解决方案均无效。
My Class:
我的课:
package aes;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.JOptionPane;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class EncryptionExample {
private static SecretKeySpec key;
private static IvParameterSpec ivSpec;
private static Cipher cipher;
private static byte[] keyBytes;
private static byte[] ivBytes;
private static int enc_len;
public static void generateKey() throws Exception
{
String complex = new String ("9#82jdkeo!2DcASg");
keyBytes = complex.getBytes();
key = new SecretKeySpec(keyBytes, "AES");
complex = new String("@o9kjbhylK8(kJh7"); //just some randoms, for now
ivBytes = complex.getBytes();
ivSpec = new IvParameterSpec(ivBytes);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
public static String encrypt(String packet) throws Exception
{
byte[] packet2 = packet.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted = new byte[cipher.getOutputSize(packet2.length)];
enc_len = cipher.update(packet2, 0, packet2.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);
return packet = new String(encrypted);
}
public static String decrypt(String packet) throws Exception
{
byte[] packet2 = packet.getBytes();
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(packet2, 0, enc_len, decrypted, 0);
HERE EXCEPTION>>>>> dec_len += cipher.doFinal(decrypted, dec_len); <<<<<<<<<
return packet = new String(decrypted);
}
// and display the results
public static void main (String[] args) throws Exception
{
// get the text to encrypt
generateKey();
String inputText = JOptionPane.showInputDialog("Input your message: ");
String encrypted = encrypt(inputText);
String decrypted = decrypt(encrypted);
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
"Encrypted: " + new String(encrypted) + "\n"
+ "Decrypted: : " + new String(decrypted));
.exit(0);
}
}
The thing is, when I decrypt strings (about 4/10 of shots), I get that exception:
问题是,当我解密字符串(大约 4/10 的镜头)时,我得到了那个例外:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:479)
at javax.crypto.Cipher.doFinal(Cipher.java:2068)
at aes.EncryptionExample.deszyfrujBez(EncryptionExample.java:HERE tag)
at aes.EncryptionExample.main(EncryptionExample.java:Main starting)
Does anybody know what to change here (key? *.doFinal() method?) to make it work?
有没有人知道在这里更改什么(键?*.doFinal() 方法?)以使其工作?
@ for those curious - methods have to be static, as this is a part of something bigger ;)
@对于那些好奇的人 - 方法必须是静态的,因为这是更大的东西的一部分;)
回答by Henry
The result of encryption is binary data. In most cases it cannot be interpreted as a valid string encoding. So the call to new String(encrypted)
will most likely distort the encrypted bytes and after doing packet.getBytes()
you end up with a byte array with different content.
加密的结果是二进制数据。在大多数情况下,它不能被解释为有效的字符串编码。因此,对 的调用new String(encrypted)
很可能会扭曲加密的字节,并且在这样做之后packet.getBytes()
您最终会得到一个具有不同内容的字节数组。
The decryption now fails because the cypher text has been changed. The padding bytes are not correctly recovered and cannot be removed.
解密现在失败,因为密码文本已更改。填充字节未正确恢复且无法删除。
To fix that, don't convert the cypher text to a string, keep the byte array.
要解决这个问题,不要将密码文本转换为字符串,而是保留字节数组。
回答by Jim Flood
When you use byte[] packet2 = packet.getBytes()
you are converting the string based on the default encoding, which could be UTF-8, for example. That's fine. But then you convert the ciphertext back to a string like this: return packet = new String(encrypted)
and this can get you into trouble if this does not round-trip to the same byte array later in decrypt() with another byte[] packet2 = packet.getBytes()
.
当您使用时,byte[] packet2 = packet.getBytes()
您将根据默认编码转换字符串,例如,可以是 UTF-8。没关系。但是随后您将密文转换回这样的字符串:return packet = new String(encrypted)
如果稍后在解密()中没有与另一个byte[] packet2 = packet.getBytes()
.
Try this instead: return packet = new String(encrypted, "ISO-8859-1")
, and byte[] packet2 = packet.getBytes("ISO-8859-1")
-- it's not what I would prefer, but it should round-trip the byte arrays.
试试这个:return packet = new String(encrypted, "ISO-8859-1")
, 和byte[] packet2 = packet.getBytes("ISO-8859-1")
-- 这不是我喜欢的,但它应该来回字节数组。