简体   繁体   English

Java密码填充错误

[英]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). 我是Java的新手,它尝试使用CipherSecretKey加密和解密两条文本消息,如下面的代码bellow(第241行的代码)所示。 Whenever I tries to Decrypt this encrypted message, I get an error saying: 每当我尝试Decrypt此加密消息时,都会收到一条错误消息:
javax.crypto.BadPaddingException: Given final block not properly padded javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher 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. 我在这段代码中使用了3个线程和两个分别称为q1和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的共享实例。 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. Cipher不是线程安全的,并且在SecurityDecryptionAlgorithmSecurityEncryptionAlgorithm都使用了SecurityDecryptionAlgorithm ,因此它要求麻烦...而麻烦的是内部缓冲区已损坏并引发了所显示的异常。

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 . 要解决此问题,只需对每个加密/解密(首选解决方案)使用实例密码,为每个线程创建一个实例,或者使SecurityDecryptionAlgorithmSecurityEncryptionAlgorithm的静态方法同步,并为每个实例提供不同的Cipher实例。

I would remove Cipher from Global5 and instantiate a new one on each call to encrypt or decrypt. 我将从Global5删除Cipher ,并在每次调用时实例化一个新的加密或解密对象。

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. 如果要使用相同的Cipher对象实例进行加密或解密,则必须特别小心, 尤其是当有多个线程访问同一Cipher对象(在您的情况下)时,因为它内部使用了缓冲区,填充等,因此即使您可以指定适当的填充方案,就像您指定PKCS5Padding或者您不指定任何填充(使用AES/ECB/NoPadding或使用ECB模式DES/ECB/PKCS5Padding ), 则很可能会遇到异常DES/ECB/PKCS5Padding javax.crypto.BadPaddingException: Given final block not properly padded并且javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher因为内部的Cipher对象被弄乱了。

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. 现在,由于您使用的是相同的Cipher对象,因此即使您正确指定了padding等,但由于它是同一个对象,仍然会出现与padding相关的异常。

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 . 如果将CBC模式用于Cipher对象,则还应该提供IvParameterSpec对象,否则您可能会遇到java.security.InvalidKeyException异常。

Read this answer . 阅读此答案

Also, it is recommended to use CBC mode over ECB mode. 另外,建议使用CBC模式而不是ECB模式。

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: 因此,您的最终代码如下所示,它将毫无例外地运行,但是您指定的消息数与答案- 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 PS:我已经清理了一些代码以关闭您的Scanner对象,等等,您也应该注意这些事情

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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