In AES decryption, "Given final block not properly padded" occurred

16,681

you are calling doFinal multiple times. or at least trying to.

when you read data, not all data arrives or is read into the buffer at once. so you decrypt some and then read again. that is all ok.

but when you do that, you are calling doFinal each time, instead of update. this is wrong and is the cause of the error. instead, replace doFinal with update and then add an extra doFinal once you have finished reading all data (there is a doFinal() that takes no arguments for exactly this reason).

see http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html

also see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29 for why ecb mode is often not a good idea (look at the penguin pictures).

Share:
16,681
Han
Author by

Han

SOreadytohelp

Updated on June 04, 2022

Comments

  • Han
    Han almost 2 years

    I'm doing a simple encryption file transfer system and now stopped by a run time exception:

    Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
        at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
        at javax.crypto.Cipher.doFinal(Cipher.java:2087)
        at ftpclient.FTPClient.main(FTPClient.java:82)
    

    I tried to debug my code using a string to encrypt and decrypt with the same key and it works. However, when I tried to transfer stream from the file, this exception always comes.

    Here are the codes of both sides. At first they will exchange symmetric key (AES key) via RSA and then transfer large files via AES encryption. We can focus on the last part of each code where the files are encrypted and decrypted by AES key.

    Server Side:

    package ftpserver;
    
    import java.io.*;
    import java.net.*;
    import javax.crypto.*;
    import java.security.*;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64; 
    /**
     *
     * @author Han
     */
    public class FTPServer {
        public static void main(String[] args) throws Exception {
    
            //generate symmetric key and initialize cipher for AES
            SecretKey skey = null;
            Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
    
            KeyGenerator kg = KeyGenerator.getInstance("AES");
            kg.init(128);
            skey = kg.generateKey();
    
            //get public key of the receive side
            final String PUBLIC_KEY_PATH = "key_b.public";
            PublicKey publickey = null;
            try {
            FileInputStream fis;
            fis = new FileInputStream(PUBLIC_KEY_PATH);
            ObjectInputStream oin = new ObjectInputStream(fis);
            publickey = (PublicKey) oin.readObject();
            oin.close();
            } catch (FileNotFoundException e) {
            e.printStackTrace();
            } catch (IOException e) {
            e.printStackTrace();
            } catch (ClassNotFoundException e) {
            e.printStackTrace();
            };
    
            //encrypte symmetric key with own private key and send out
            Cipher rsa = Cipher.getInstance("RSA");
            rsa.init(Cipher.ENCRYPT_MODE, publickey);
            byte cipherSKey[] = rsa.doFinal(skey.getEncoded());
            //System.out.println(skey); //debug
    
        //create tcp server socket
            ServerSocket tcp = new ServerSocket(2000);
            Socket client = tcp.accept();
    
            //get input&output stream from the TCP connection
            InputStream in = client.getInputStream();
        OutputStream out = client.getOutputStream();
    
            //generate a file input stream to get stream from file
        File sentFile = new File("F:\\test.txt");
            FileInputStream fin = new FileInputStream(sentFile);
    
            //send encrypted symmetric key first
            out.write("Symmetric Key:\r\n".getBytes());
            out.write(cipherSKey);
    
            DataInputStream din = new DataInputStream(in);
            while(true)
            {
                if(din.readLine().equals("Received."))
                {
                    System.out.println("Send key successfully.");
                    break;
                }
    
            };
    
            //send files
        int count;
            byte[] bytearray = new byte[8192];
            byte[] cipherbuffer;
            while((count = fin.read(bytearray))>0)
        {
            cipherbuffer = Base64.encodeBase64(aes.doFinal(bytearray));
            out.write(cipherbuffer,0,cipherbuffer.length);
            System.out.println(count+" bytes have been sent.");
            };
    
            out.flush();
            out.close();
    
            client.close();
    
    
            }
    }
    

    Client Side:

    package ftpclient;
    
    import java.io.*;
    import java.net.*;
    import java.security.PrivateKey;
    import javax.crypto.*;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    /**
     *
     * @author Han
     */
    public class FTPClient {
    
    public static void main(String[] args) throws Exception 
        {
                //get the private key of this side
    
    
            final String PUBLIC_KEY_PATH = "key_b.privat";
            PrivateKey privatkey = null;
            try {
            FileInputStream fis;
            fis = new FileInputStream(PUBLIC_KEY_PATH);
            ObjectInputStream oin = new ObjectInputStream(fis);
            privatkey = (PrivateKey) oin.readObject();
            oin.close();
            } catch (FileNotFoundException e) {
            e.printStackTrace();
            } catch (IOException e) {
            e.printStackTrace();
            } catch (ClassNotFoundException e) {
            e.printStackTrace();
            };
    
            Cipher rsa = Cipher.getInstance("RSA");
            rsa.init(Cipher.DECRYPT_MODE, privatkey);
    
            //create tcp client socket
            Socket tcp = new Socket("192.168.1.185",2000);        
        InputStream in = tcp.getInputStream();
            OutputStream out = tcp.getOutputStream();
            DataInputStream din = new DataInputStream(in);
    
            //receive symmetric key from server
            byte keybuffer[] = new byte[128];
            SecretKey skey = null;
    
            while(true)
            {
                if(din.readLine().equals("Symmetric Key:"))
                {
                    System.out.println("Start to receiving key...");
                    in.read(keybuffer);
                    byte[] skeycode = rsa.doFinal(keybuffer);
                    skey = new SecretKeySpec(skeycode, 0, skeycode.length, "AES");
                    out.write("Received.\r\n".getBytes());
                    break;
                }
            };
            //create cipher for symmetric decryption
            Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
            aes.init(Cipher.DECRYPT_MODE, skey);
            //System.out.println(skey); //debug
    
            //create file stream
            FileOutputStream fos = new FileOutputStream("E:\\test_cp.txt");
    
        int count;
            int i = 0;
            byte[] bytearray = new byte[8192];
            byte[] buffer;
            while((count = in.read(bytearray)) > 0)
            {
                buffer = (aes.doFinal(Base64.decodeBase64(bytearray)));
                            fos.write(buffer,0,buffer.length);   
                            i +=count;
                            System.out.println(i+" bytes have been received.");
            };
    
    
            fos.flush();
            fos.close();
            in.close();
    
            tcp.close();
            System.out.println("File Transfer completed");
    
        }
    
    }