0

我正在尝试加密和解密我的所有密码都使用 AES 存储在其中的文件。

该算法在加密部分运行良好。但是在解密时它会抛出错误

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.access$100(SearchDoc.java:52)
        at SearchDoc$2$1.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.access$400(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.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)

这里有什么问题?

代码:

//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;
}

新的 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;
}

}
4

2 回答 2

5

使用 just AESas cipher instance 不会声明如何填充最终块。这就是加密和解密可能不同的原因。

请改用以下具体密码实例之一(取决于您的加密模式):

AES/CBC/NoPadding
AES/CBC/PKCS5Padding
AES/ECB/NoPadding
AES/ECB/PKCS5Padding

您可以在此处找到支持的密码列表

于 2015-04-13T14:24:20.877 回答
2

假设您逐行加密了原始明文,您将无法逐行解密它。密文可以包含任何字节值,包括\n. 因此,如果您在单独的调用中加密了每个明文行,您有时会得到一个密文“行”,其字节对应于\n. 当您现在想要解密它时,这是不可能的,因为这些 Cipher 调用之间的边界是不同的。

要解决此问题,您需要在一次调用中加密整个文档(使用CipherInputStream/CipherOutputStream如果您有内存问题)或单独加密每一行,但请确保您知道密文中的边界。

例如,后一种方法可以通过以\n不存在于其中的方式对每个部分密文进行编码来完成。例如,您可以将其编码为 Base 64,但这会使您的密文膨胀约 33%。

我建议您使用前一种方法进行一次调用。


正如 flo 所提到的,最好使用完全限定的密码字符串,因为不同的 Java 版本可能使用不同的默认操作模式或填充,您最终可能会得到不可恢复的密文。

于 2015-04-13T15:06:23.003 回答