Java 填充异常:给定最终块未正确填充
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29607500/
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
Padding Exception: Given final block not properly padded
提问by user2820823
I am trying to encrypt and decrypt my file in which all my passwords are stored using AES.
我正在尝试加密和解密我的文件,其中所有密码都使用 AES 存储。
The algorithm works fine on encryption part. But while decryption it throws the error
该算法在加密部分运行良好。但是在解密时它会抛出错误
Message:Given final block not properly padded
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2121)
at SearchDoc.dec_file(SearchDoc.java:327)
at SearchDoc.access0(SearchDoc.java:52)
at SearchDoc.actionPerformed(SearchDoc.java:227)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
What is the problem here?
这里有什么问题?
code:
代码:
//Starting decryption
try{
byte[] key = c_key.getBytes("ISO-8859-1");
key = Arrays.copyOf(key, 16); // use only first 128 bit
//System.out.println(Arrays.toString(key));
SecretKeySpec SecKey = new SecretKeySpec(key, "AES");
Cipher AesCipher = Cipher.getInstance("AES");
AesCipher.init(Cipher.DECRYPT_MODE, SecKey);
BufferedReader breader = new BufferedReader(new FileReader("download/enc_"+file));
String line;
boolean bool = false;
File f = new File(file);
bool = f.createNewFile();
if(bool==false){
f.delete();
bool = f.createNewFile();
}
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
while ((line = breader.readLine()) != null){
byte[] cipher=null;
byte[] plain=null;
cipher=line.getBytes("ISO-8859-1");
plain=AesCipher.doFinal(cipher);
out.println(new String(plain,"ISO-8859-1"));
}
out.close();
return 1;
}
catch(Exception dcf){
System.out.println("Message:"+dcf.getMessage());
dcf.printStackTrace();
return 0;
}
NEW AES CODE:
新的AES代码:
import java.security.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.*;
import sun.misc.*;
public class AESencrp {
private static final String ALGO = "AES";
private static final byte[] keyValue =
new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't',
'S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };
public static String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}
}
回答by flo
Using just AES
as cipher instance does not declare how the final block is padded. This is why encryption and decryption may differ.
使用AES
as cipher 实例不会声明如何填充最终块。这就是加密和解密可能不同的原因。
Use one of the following, concrete cipher instances instead (depending on your encryption mode):
改用以下具体密码实例之一(取决于您的加密模式):
AES/CBC/NoPadding
AES/CBC/PKCS5Padding
AES/ECB/NoPadding
AES/ECB/PKCS5Padding
AES/CBC/NoPadding
AES/CBC/PKCS5Padding
AES/ECB/NoPadding
AES/ECB/PKCS5Padding
You can find a list of the supported ciphers here
您可以在此处找到支持的密码列表
回答by Artjom B.
Assuming you encrypted the original plaintext linewise, you will not be able to decrypt it linewise. Ciphertext may contain anybyte value, including the ones for \n
. So, if you encrypted every plaintext line in a separate invocation, you will sometimes get a ciphertext "line" that has a byte that corresponds to \n
. When you now want to decrypt this, it won't be possible, because the boundaries between those Cipher invocations are different.
假设您对原始明文逐行加密,您将无法逐行解密。密文可以包含任何字节值,包括\n
. 因此,如果您在单独的调用中加密每个明文行,您有时会得到一个密文“行”,其中的字节对应于\n
. 当您现在想要解密它时,这是不可能的,因为这些 Cipher 调用之间的界限是不同的。
To fix this, you need to either encrypt the whole document in one invocation (use CipherInputStream
/CipherOutputStream
if you have memory concerns) or encrypt every line separately, but ensure that you know the boundaries in the ciphertext.
要解决此问题,您需要在一次调用中加密整个文档(使用CipherInputStream
/CipherOutputStream
如果您有内存问题)或单独加密每一行,但要确保您知道密文中的边界。
The latter approach can be done for example by encoding each partial ciphertext in such a way that \n
is not present in it. You can for example encode it as Base 64, but that will blowup your ciphertext by ~33%.
例如,后一种方法可以通过以其中\n
不存在的方式对每个部分密文进行编码来完成。例如,您可以将其编码为 Base 64,但这会使您的密文增加约 33%。
I would suggest that you use the former approach with a single invocation.
我建议您在一次调用中使用前一种方法。
As flo mentioned, it is always best to use fully-qualified Cipher strings, because different Java versions may use different default for mode of operation or padding and you may end up with unrecoverable ciphertext.
正如 flo 所提到的,最好使用完全限定的密码字符串,因为不同的 Java 版本可能使用不同的默认操作模式或填充,最终可能会得到不可恢复的密文。