我是java新手并尝试使用Cipher
和SecretKey
加密和解密两条短信,如下面的代码所示(第241行,位于最底部)。每当我尝试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
我在这段代码中使用了3个Threads,并且有两个名为q1和q2的缓冲区/队列。首先,我将消息放入缓冲区/队列中。然后在下一节课中,我检索该消息并对其进行加密,然后发送到下一节课。然后该类将再次将其放入缓冲区/队列中。最后,在最后一个类中,它将从缓冲区中检索并解密它。这就是问题发生的地方。发生同步错误。我一直在努力想象这个错误很多天,没有运气。其他在线文档也没有帮助。如果您可以编辑此代码或向我显示示例
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();
}
}
}
如果您复制并通过此程序,它将在您的计算机上运行
答案 0 :(得分:2)
在不看代码的情况下,我可以看到它正在使用Cipher
的共享实例。 Cipher
不是线程安全的,它在SecurityDecryptionAlgorithm
和SecurityEncryptionAlgorithm
都使用,所以它要求麻烦...而麻烦的是内部缓冲区被破坏并抛出你正在显示的异常
要解决此问题,只需对每个加密/解密(首选解决方案)进行实例密码,为每个线程创建一个实例,或者使SecurityDecryptionAlgorithm
和SecurityEncryptionAlgorithm
中的静态方法同步,并为每个实例提供一个Cipher
的不同实例。
我会从Cipher
删除Global5
并在每次调用时实例化一个新的加密或解密。
为了使其更加明显,此代码调用
c.init(Cipher.ENCRYPT_MODE, sk);
和
c.init(Cipher.DECRYPT_MODE, sk);
在同一个实例上......我确信它会使密码更加混乱。
答案 1 :(得分:2)
如果您使用Cipher
对象的相同实例进行加密或解密,,特别是,当多于1个线程将访问同一Cipher
个对象时,您必须要小心(在你的情况下的情况)因为它在内部使用缓冲区,填充等等所以即使你指定了适当的填充方案,就像你指定PKCS5Padding
或者你没有指定任何填充(使用AES/ECB/NoPadding
或使用ECB模式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对象已经搞砸了。
现在,既然您使用了相同的Cipher
对象,那么即使您正确指定了填充等,但仍然会得到与填充相关的异常,因为它是同一个对象。
如果将CBC
模式用于Cipher对象,则还应提供IvParameterSpec
对象,否则您可能会遇到java.security.InvalidKeyException
之类的异常。
此外,建议在CBC
模式下使用ECB
模式。
因此,您的最终代码如下所示,该代码将无异常运行,但是您指定的消息数量为 - How many messages to send:
P.S。:我已经完成了一些代码清理以关闭你的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();
}
}
}