0

I am trying to encrypt and decrypt my file in which all my passwords are stored using 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.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)

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:

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

}
jww
  • 97,681
  • 90
  • 411
  • 885
user2820823
  • 86
  • 1
  • 1
  • 9

2 Answers2

5

Using just AES as cipher instance does not declare how the final block is padded. This is why encryption and decryption may differ.

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

You can find a list of the supported ciphers here

flo
  • 9,713
  • 6
  • 25
  • 41
  • still not working. Can you tell me how that should work. – user2820823 Apr 14 '15 at 06:48
  • see the answer of Artjom regarding linewise encryption/decryption – flo Apr 14 '15 at 07:36
  • I tried now I am getting an error `Input length must be multiple of 16 when decrypting with padded cipher` – user2820823 Apr 14 '15 at 09:50
  • what exactly have you tried? Maybe https://stackoverflow.com/questions/3954611/aes-encript-and-decript-with-apache-base64 helps. – flo Apr 14 '15 at 10:38
  • 2
    Seems like the data you want to decrypt is not the exact output of the encryption method. I could reproduce the error only when adding additional chars to the encrypted string for decoding (`decrypt(encrypt("secrect") + "bar)"`). **Note**: The code you posted uses `AES/ECB/PKCS5Padding` (Java's default), which should only be used when encrypting a single block. See: https://stackoverflow.com/questions/1220751/how-to-choose-an-aes-encryption-mode-cbc-ecb-ctr-ocb-cfb` – flo Apr 14 '15 at 14:18
2

Assuming you encrypted the original plaintext linewise, you will not be able to decrypt it linewise. Ciphertext may contain any byte 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.

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.

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%.

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222