简体   繁体   中英

Java Cipher padding Error

I am new to java and trying to encrypt and decrypt two text messages using Cipher and SecretKey as shown in the code bellow(Line 241, at the very bottom). Whenever I tries to Decrypt this encrypted message, I get an error saying:
javax.crypto.BadPaddingException: Given final block not properly padded javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
I am using 3 Threads in this code and two buffers/queues called q1 and q2. At first, I put a message in a buffer/queue. Then in the next class, I retrieve that message and encrypt it, and send to the next class. Then that class will put it in a buffer/queue again. Finally, at the last class, it will retrieve from the buffer and decrypt it. This is where the problem happens. There is a Synchronization error going on. I have been trying to figure this error for many days now and no luck. Other online documentations didn't help either. I would greatly appreciate if you could edit this code or show me with an example

import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.Signature;
import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;



class Q5 { //Queue/Buffer   
    byte[] shipmentConfirmation;//will include the actual message content been delivered
    boolean valueSet = false;
    synchronized byte[] get() 
    {       
        while(!valueSet) 
        try 
        {
            wait();
        } 
        catch(InterruptedException e) 
        {
            System.out.println("InterruptedException caught");
        }
        //System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return shipmentConfirmation;
    }
    synchronized void put(byte[] shipmentCinfirm) 
    {
        while(valueSet)
        try 
        {
            wait();
        } 
        catch(InterruptedException e) 
        {
            System.out.println("InterruptedException caught");
        }
        this.shipmentConfirmation = shipmentCinfirm;
        valueSet = true;
        //System.out.println("Put: " + n);
        notify();
    }
}

class Global5{
    public static int sendcouter = 0;
    public static SecretKey secret_Key;
    public static Cipher desCipher;
}


//<<security pattern>> SymmetricEncryptionEncryptor
class SecurityEncryptor//<<security>> Encryptor
{
    static byte[] Encryptor(byte shipmentConfirmation[],Cipher c) throws Exception //Encryptor
    {       
        byte[] ciphertext = SecurityEncryptionAlgorithm.EncryptionAlgorithm(shipmentConfirmation,c,Global5.secret_Key);
        return ciphertext;
    }   
}
class SecurityEncryptionAlgorithm//<<security>> EncryptionAlgorithm
{
    static byte[] EncryptionAlgorithm(byte shipmentConfirmation[],Cipher c,SecretKey sk) throws Exception 
    {
        c.init(Cipher.ENCRYPT_MODE, sk);
        return c.doFinal(shipmentConfirmation);
    }
}



//<<security pattern>> aSecureAsynchronousMCReceiverConnector
class SecurityDecryptor//<<Security>> Decryptor
{
    static byte[] Decryptor(byte EncryptedShipmentConfirmation[],Cipher c,SecretKey sk) throws Exception //Decryptor
    {
        byte[] ct = SecurityDecryptionAlgorithm.DecryptionAlgorithm(EncryptedShipmentConfirmation,c,sk);
        return ct;
    }   
}
class SecurityDecryptionAlgorithm//<<Security>> DecryptionAlgorithm
{
    static byte[] DecryptionAlgorithm(byte EncryptedShipmentConfirmation[],Cipher c,SecretKey sk) throws Exception 
    {
        c.init(Cipher.DECRYPT_MODE, sk);
        return c.doFinal(EncryptedShipmentConfirmation);
    }
}



public class testFigure1 { //Main
       public static void main(String args[]) throws Exception {          
            Q5 q1 = new Q5();//creating buffer/queue
            Q5 q2 = new Q5();

            System.out.println("How many messages to send: ");
            Scanner in = new Scanner(System.in);
            int input = in.nextInt();//Get input from the supplier          

            aSupplierInterface Supplier = new aSupplierInterface(q1, input);    
            aSecuritySenderCoordinator SenderCoordinator = new aSecuritySenderCoordinator(q1, input, q2);           
            aSecurityReceiverCoordinator receive = new aSecurityReceiverCoordinator(q2, input);   
            Supplier.t_pro.join();
            SenderCoordinator.t_coordinator5.join();
            receive.t_SecurityReceiverCoordinator5.join();
            System.out.println("End of Program!");
       }   
}

class aSupplierInterface  implements Runnable //<<application Component>> aSupplierInterface
{
    Q5 q;   
    int supinput;
    Thread t_pro;//pro to represent producer or suppler
    aSupplierInterface(Q5 qq, int input)
    {
        supinput = input;
        this.q = qq;
        t_pro = new Thread(this, "Producer");
        t_pro.start();
    }
    public void run() 
    {
        int i = 0;
        String shipment;
        byte[] shipmentConfirmation;
        while(i<supinput)
        {
            i++;
            shipment = "This is the Delivery Number: "+ i;
            shipmentConfirmation = shipment.getBytes();

            q.put(shipmentConfirmation);//Putting supplier's goods in a queue/buffer            
        }   
    }       
}

class aSecuritySenderCoordinator implements Runnable //<<security coordinator>> aSecuritySenderCoordinator
{
    Q5 q;
    Q5 q2;
    Thread t_coordinator5;
    int supinput;

    public aSecuritySenderCoordinator(Q5 qq, int input, Q5 q2) throws Exception
    {       
        supinput=input;
        this.q = qq;    
        this.q2=q2;
        t_coordinator5 = new Thread(this, "coordinator5");
        t_coordinator5.start();
    }

    public void run() 
    {
        byte[] pkShipmentConfirmation;
        byte[] shipmentConfirmation;
        int i = 0;
        while(i<supinput) 
        {               
            i++;

                //Getting goods that supplier has put in the queue previously
            pkShipmentConfirmation=q.get();//This will contain content of the message/delivery you are sending
            KeyGenerator keygen;
            try {
            keygen = KeyGenerator.getInstance("DES");
            Global5.sendcouter++;//To Create the key once
            if(Global5.sendcouter==1)//Create once
            {
                Global5.secret_Key = keygen.generateKey();
                Global5.desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            }           
            //String st1 = new String(pkShipmentConfirmation);//just to print a message
            //System.out.println("*ORIGINAL MESSAGE:"+st1);    
            shipmentConfirmation = SecurityEncryptor.Encryptor(pkShipmentConfirmation,Global5.desCipher);//Encrypting 


            new anAsynchronousMCReceiver(q2, shipmentConfirmation);     

            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}




class anAsynchronousMCReceiver 
{ //<<communication pattern>> anAsynchronousMCReceiver
       Q5 q;

       anAsynchronousMCReceiver( Q5 q2, byte[] shipmentConfirm) throws Exception
       {
           this.q = q2;
           q.put(shipmentConfirm);  //Entering received data in to the Queue/Buffer 
       }
}



class aSecurityReceiverCoordinator implements Runnable//<<security coordinator>> aSecurityReceiverCoordinator
{       
    Thread t_SecurityReceiverCoordinator5;  
    Q5 q;
    int supinput;
    byte[]encryptedShipmentConfirmation;
    public aSecurityReceiverCoordinator(Q5 q2, int input) throws Exception
    {  
        this.q = q2;    
        supinput = input;
        t_SecurityReceiverCoordinator5 = new Thread(this, "SecurityReceiverCoordinator5");
        t_SecurityReceiverCoordinator5.start();

    }
    public void run() 
    {
        try {
            int i = 0;
            while(i<supinput) 
            {           
                i++;
                encryptedShipmentConfirmation = q.get();                
                byte[] confirmation = SecurityDecryptor.Decryptor(encryptedShipmentConfirmation,Global5.desCipher,Global5.secret_Key);//ERROR HAPPENS HERE              
                String shipConfirmation = new String(confirmation);

                System.out.println("AT DelivertyOrder: " +  shipConfirmation);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

If you copy and past this program, it will run on your computer

Without looking too much at the code, I can see that it's using a shared instance of Cipher . Cipher is not thread safe and it's used both in SecurityDecryptionAlgorithm and SecurityEncryptionAlgorithm so it's asking for trouble... and the trouble is that the internal buffer gets corrupted and throws the exception you are showing.

To fix this, just instance cipher on each encryption/decryption (preferred solution), create one instance per thread, or make the static methods from SecurityDecryptionAlgorithm and SecurityEncryptionAlgorithm synchronized and provide each one with a different instance of Cipher .

I would remove Cipher from Global5 and instantiate a new one on each call to encrypt or decrypt.

To make this more visible, this code calls

c.init(Cipher.ENCRYPT_MODE, sk);

and

c.init(Cipher.DECRYPT_MODE, sk);

On the same instance... which I'm sure it confuses the cipher even further.

Multi-threading issue:

You have to be careful if you are using same instance of Cipher object for encryption or decryption, and specially when more than 1 thread will access the same Cipher object (situation in your case) because it internally uses buffers, paddings etc. so even if you specify appropriate padding scheme, like you were specifying PKCS5Padding OR you do not specify any padding (using AES/ECB/NoPadding or using ECB mode DES/ECB/PKCS5Padding ), you are most likely to get the exception you were getting - javax.crypto.BadPaddingException: Given final block not properly padded and javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher because internally Cipher object was getting messed up.

Now, since you were using same Cipher object so even though you specified padding etc. correctly but still you were getting padding related exceptions because it was same object.

Cryptography issue:

If CBC mode is used for Cipher object then a IvParameterSpec object should also be provided otherwise you are likely to run into exceptions like java.security.InvalidKeyException .

Read this answer .

Also, it is recommended to use CBC mode over ECB mode.

Read this answer.

Updated code

So, your final code looks as below, which will run with no exception, however number of messages you specify with the answer to - How many messages to send:

PS: I have done some code clean up to close your Scanner object etc., you should pay attention to these kind of things as well

import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;



class Q5 { //Queue/Buffer   
    byte[] shipmentConfirmation;//will include the actual message content been delivered
    boolean valueSet = false;
    synchronized byte[] get() 
    {       
        while(!valueSet) 
        try 
        {
            wait();
        } 
        catch(InterruptedException e) 
        {
            System.out.println("InterruptedException caught");
        }
        //System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return shipmentConfirmation;
    }
    synchronized void put(byte[] shipmentCinfirm) 
    {
        while(valueSet)
        try 
        {
            wait();
        } 
        catch(InterruptedException e) 
        {
            System.out.println("InterruptedException caught");
        }
        this.shipmentConfirmation = shipmentCinfirm;
        valueSet = true;
        //System.out.println("Put: " + n);
        notify();
    }
}

class Global5{
    public static int sendcouter = 0;
    public static SecretKey secret_Key;
    public static Cipher desCipher;
}


//<<security pattern>> SymmetricEncryptionEncryptor
class SecurityEncryptor//<<security>> Encryptor
{
    static byte[] Encryptor(byte shipmentConfirmation[],Cipher c) throws Exception //Encryptor
    {       
        byte[] ciphertext = SecurityEncryptionAlgorithm.EncryptionAlgorithm(shipmentConfirmation,c,Global5.secret_Key);
        return ciphertext;
    }   
}
class SecurityEncryptionAlgorithm//<<security>> EncryptionAlgorithm
{
    static byte[] EncryptionAlgorithm(byte shipmentConfirmation[],Cipher c,SecretKey sk) throws Exception 
    {
        byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0};
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        c.init(Cipher.ENCRYPT_MODE, sk, ivspec);
        return c.doFinal(shipmentConfirmation);
    }
}



//<<security pattern>> aSecureAsynchronousMCReceiverConnector
class SecurityDecryptor//<<Security>> Decryptor
{
    static byte[] Decryptor(byte EncryptedShipmentConfirmation[],Cipher c,SecretKey sk) throws Exception //Decryptor
    {
        byte[] ct = SecurityDecryptionAlgorithm.DecryptionAlgorithm(EncryptedShipmentConfirmation,c,sk);
        return ct;
    }   
}
class SecurityDecryptionAlgorithm//<<Security>> DecryptionAlgorithm
{
    static byte[] DecryptionAlgorithm(byte EncryptedShipmentConfirmation[],Cipher c,SecretKey sk) throws Exception 
    {
        byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0};
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        c.init(Cipher.DECRYPT_MODE, sk, ivspec);
        return c.doFinal(EncryptedShipmentConfirmation);
    }
}



public class testFigure1 { //Main
       public static void main(String args[]) throws Exception {          
            Q5 q1 = new Q5();//creating buffer/queue
            Q5 q2 = new Q5();

            System.out.println("How many messages to send: ");
            Scanner in = new Scanner(System.in);
            int input = in.nextInt();//Get input from the supplier          
            in.close();

            aSupplierInterface Supplier = new aSupplierInterface(q1, input);    
            aSecuritySenderCoordinator SenderCoordinator = new aSecuritySenderCoordinator(q1, input, q2);           
            aSecurityReceiverCoordinator receive = new aSecurityReceiverCoordinator(q2, input);   
            Supplier.t_pro.join();
            SenderCoordinator.t_coordinator5.join();
            receive.t_SecurityReceiverCoordinator5.join();
            System.out.println("End of Program!");
       }   
}

class aSupplierInterface  implements Runnable //<<application Component>> aSupplierInterface
{
    Q5 q;   
    int supinput;
    Thread t_pro;//pro to represent producer or suppler
    aSupplierInterface(Q5 qq, int input)
    {
        supinput = input;
        this.q = qq;
        t_pro = new Thread(this, "Producer");
        t_pro.start();
    }
    public void run() 
    {
        int i = 0;
        String shipment;
        byte[] shipmentConfirmation;
        while(i<supinput)
        {
            i++;
            shipment = "This is the Delivery Number: "+ i;
            shipmentConfirmation = shipment.getBytes();

            q.put(shipmentConfirmation);//Putting supplier's goods in a queue/buffer            
        }   
    }       
}

class aSecuritySenderCoordinator implements Runnable //<<security coordinator>> aSecuritySenderCoordinator
{
    Q5 q;
    Q5 q2;
    Thread t_coordinator5;
    int supinput;

    public aSecuritySenderCoordinator(Q5 qq, int input, Q5 q2) throws Exception
    {       
        supinput=input;
        this.q = qq;    
        this.q2=q2;
        t_coordinator5 = new Thread(this, "coordinator5");
        t_coordinator5.start();
    }

    public void run() 
    {
        byte[] pkShipmentConfirmation;
        byte[] shipmentConfirmation;
        int i = 0;
        while(i<supinput) 
        {               
            i++;

                //Getting goods that supplier has put in the queue previously
            pkShipmentConfirmation=q.get();//This will contain content of the message/delivery you are sending
            KeyGenerator keygen;
            try {
            keygen = KeyGenerator.getInstance("DES");
            Global5.sendcouter++;//To Create the key once
            if(Global5.sendcouter==1)//Create once
            {
                Global5.secret_Key = keygen.generateKey();
                Global5.desCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            }           
            //String st1 = new String(pkShipmentConfirmation);//just to print a message
            //System.out.println("*ORIGINAL MESSAGE:"+st1);    
            shipmentConfirmation = SecurityEncryptor.Encryptor(pkShipmentConfirmation,Cipher.getInstance("DES/CBC/PKCS5Padding"));//Encrypting 


            new anAsynchronousMCReceiver(q2, shipmentConfirmation);     

            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}




class anAsynchronousMCReceiver 
{ //<<communication pattern>> anAsynchronousMCReceiver
       Q5 q;

       anAsynchronousMCReceiver( Q5 q2, byte[] shipmentConfirm) throws Exception
       {
           this.q = q2;
           q.put(shipmentConfirm);  //Entering received data in to the Queue/Buffer 
       }
}



class aSecurityReceiverCoordinator implements Runnable//<<security coordinator>> aSecurityReceiverCoordinator
{       
    Thread t_SecurityReceiverCoordinator5;  
    Q5 q;
    int supinput;
    byte[]encryptedShipmentConfirmation;
    public aSecurityReceiverCoordinator(Q5 q2, int input) throws Exception
    {  
        this.q = q2;    
        supinput = input;
        t_SecurityReceiverCoordinator5 = new Thread(this, "SecurityReceiverCoordinator5");
        t_SecurityReceiverCoordinator5.start();

    }
    public void run() 
    {
        try {
            int i = 0;
            while(i<supinput) 
            {           
                i++;
                encryptedShipmentConfirmation = q.get();                
                byte[] confirmation = SecurityDecryptor.Decryptor(encryptedShipmentConfirmation,Cipher.getInstance("DES/CBC/PKCS5Padding"),Global5.secret_Key);//ERROR HAPPENS HERE              
                String shipConfirmation = new String(confirmation);

                System.out.println("AT DelivertyOrder: " +  shipConfirmation);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM