[英]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的新手,它尝试使用Cipher
和SecretKey
加密和解密两条文本消息,如下面的代码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
不是线程安全的,并且在SecurityDecryptionAlgorithm
和SecurityEncryptionAlgorithm
都使用了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
. 要解决此问题,只需对每个加密/解密(首选解决方案)使用实例密码,为每个线程创建一个实例,或者使SecurityDecryptionAlgorithm
和SecurityEncryptionAlgorithm
的静态方法同步,并为每个实例提供不同的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. 在同一情况下...我确信它会使密码更加混乱。
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相关的异常。
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
异常。
Also, it is recommended to use CBC
mode over ECB
mode. 另外,建议使用CBC
模式而不是ECB
模式。
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.