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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:18:05  来源:igfitidea点击:

Padding Exception: Given final block not properly padded

javaencryptionaesbadpaddingexception

提问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 AESas cipher instance does not declare how the final block is padded. This is why encryption and decryption may differ.

使用AESas 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/CipherOutputStreamif 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 \nis 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 版本可能使用不同的默认操作模式或填充,最终可能会得到不可恢复的密文。