Java 服务器端加密消息的解密
我正在开发一个客户机-服务器应用程序。我必须使用非对称加密技术。客户端对其消息进行加密,并创建数字签名 我将消息和签名存储在一个向量中,然后将这个向量发送到服务器。 服务器接收这个向量 在服务器端,首先我检查签名以查看服务器是否与正确的客户端通信,当签名良好时,我尝试解密消息,但解密的结果不好。 问题只涉及加密/解密,其余代码我没有问题 客户端:Java 服务器端加密消息的解密,java,encryption,cryptography,digital-signature,encryption-asymmetric,Java,Encryption,Cryptography,Digital Signature,Encryption Asymmetric,我正在开发一个客户机-服务器应用程序。我必须使用非对称加密技术。客户端对其消息进行加密,并创建数字签名 我将消息和签名存储在一个向量中,然后将这个向量发送到服务器。 服务器接收这个向量 在服务器端,首先我检查签名以查看服务器是否与正确的客户端通信,当签名良好时,我尝试解密消息,但解密的结果不好。 问题只涉及加密/解密,其余代码我没有问题 客户端: private void payActionPerformed(java.awt.event.ActionEvent evt) { Data
private void payActionPerformed(java.awt.event.ActionEvent evt) {
DataInputStream dis = new DataInputStream(s.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream());
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] message = concatMess.getBytes("UTF-8");
cipherText = encryptCipher.doFinal(message);
texteCrypteStr= Base64.getEncoder().encodeToString(cipherText);
System.out.println("MESSAGE: "+cipherText);
//SIGNATURE DU MESSAGE
Signature signature = Signature.getInstance("SHA1withRSA","BC");
System.out.println("Initialisation de la signature");
signature.initSign(keyPri);
System.out.println("Hachage du message");
signature.update(cipherText);
System.out.println("Generation des bytes");
bytesign = signature.sign();
String texteSignStr= Base64.getEncoder().encodeToString(bytesign);
System.out.println("CLIENT SIGNATURE: "+texteSignStr);
Vector vecByte = new Vector();
vecByte.add(bytesign);
vecByte.add(cipherText);
dos.writeObject(vecByte);
received = dis.readUTF();
}
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
String concatMess="";
int k = 0;
while(k<vec.size()){
concatMess+=vec.get(k);
if(k+1<vec.size())
concatMess+="!";
k+=1;
}
System.out.println("VECTOR:"+concatMess);
byte[] message = concatMess.getBytes(StandardCharsets.UTF_8);
cipherText = encryptCipher.doFinal(message);
System.out.println("MESSAGE byte: "+cipherText);
cipherTextString = Base64.getEncoder().encodeToString(cipherText);
服务器端:
public class PaiementHandler{
Vector<byte[]> receivedVec = new Vector<byte[]>();
String toreturn;
receivedVec = ((Vector)disr.readObject());
System.out.println("v1 "+receivedVec.get(0));
System.out.println("v2 "+receivedVec.get(1));
Vector<String> received = null;
//RECUPERATION CLE PUBLIQUE
KeyStore ksv = null;
ksv = KeyStore.getInstance("PKCS12", "BC");
ksv.load(new FileInputStream("C:\\Users\\user\\Desktop\\KEYSTORE\\keystore.p12"),"gogo".toCharArray());
System.out.println("Recuperation du certificat");
X509Certificate certif = (X509Certificate)ksv.getCertificate("toto");
System.out.println("Recuperation de la cle publique");
PublicKey publicKey = certif.getPublicKey();
//VERIFICATION DE LA SIGNATURE
System.out.println("\nVérification de la signature");
System.out.println("*** Cle publique recuperee = "+publicKey.toString());
System.out.println("Debut de verification de la signature construite");
Signature signature = Signature.getInstance("SHA1withRSA", "BC");
signature.initVerify(publicKey);
signature.update(receivedVec.get(1));
System.out.println("Verification de la signature construite");
boolean ok = signature.verify(receivedVec.get(0));
if(ok){
System.out.println("signature verified with success");
//DECHIFFREMENT DU MESSAGE
try{
Cipher dechiffrement = Cipher.getInstance("RSA", "BC");
dechiffrement.init(Cipher.DECRYPT_MODE,publicKey);
System.out.println("AVANT DECH");
byte[] texteDecode = dechiffrement.doFinal(receivedVec.get(1));
String texteDecodeStr = new String(texteDecode, "UTF-8");
System.out.println("Vecteur: "+texteDecodeStr);
}
}
公共类PaiementHandler{
Vector receivedVec=新向量();
字符串返回;
receivedVec=((Vector)disr.readObject());
System.out.println(“v1”+receivedVec.get(0));
System.out.println(“v2”+receivedVec.get(1));
接收向量=空;
//公共疗养院
密钥库ksv=null;
ksv=KeyStore.getInstance(“PKCS12”、“BC”);
load(新文件输入流(“C:\\Users\\user\\Desktop\\KEYSTORE\\KEYSTORE.p12”),“gogo.tocharray());
系统输出打印(“恢复du证书”);
X509Certificate certif=(X509Certificate)ksv.getCertificate(“toto”);
系统输出打印(“公共疗养”);
PublicKey PublicKey=certif.getPublicKey();
//签名验证
System.out.println(“\nVérification de la signature”);
System.out.println(“***Cle publique recuperee=“+publicKey.toString()”);
System.out.println(“签名构造的首次验证”);
签名签名=Signature.getInstance(“SHA1withRSA”,“BC”);
签名。初始化验证(公钥);
签名。更新(receivedVec.get(1));
System.out.println(“签字确认”);
布尔ok=signature.verify(receivedVec.get(0));
如果(确定){
System.out.println(“签名验证成功”);
//12月12日消息
试一试{
Cipher dechiffrement=Cipher.getInstance(“RSA”、“BC”);
dechiffrement.init(密码解密模式,公钥);
System.out.println(“先锋德奇”);
字节[]texteDecode=dechiffrement.doFinal(receivedVec.get(1));
String texteDecodeStr=新字符串(texteDecode,“UTF-8”);
System.out.println(“Vecteur:+texteDecodeStr”);
}
}
这是客户端发送到服务器的消息:“2222-2222-2222.30 3 1 2019-07-30 2019-07-31 90 40”。因此,此消息经过加密,并以向量形式与客户端签名一起发送到服务器(它们都是字节[])
服务器接收到这个向量,它首先检查签名,确定后再解密消息。
以下是转换为字符串时解密的结果:
�ߩ�U�5.�&�]��{��^��S?u2_��L��我������������b#��fCA�5.�里&�P�T��3.�4.��:���Rm���~�W���危险品��ga��我����虚拟现实
我不明白为什么我会有这个结果。。。
我试图像这个网站那样编写代码,但我不知道问题出在哪里我找到了解决方案,这要归功于: 我必须在base64中对加密消息的结果进行编码,并在解密之前对其进行解码 客户端:
private void payActionPerformed(java.awt.event.ActionEvent evt) {
DataInputStream dis = new DataInputStream(s.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream());
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] message = concatMess.getBytes("UTF-8");
cipherText = encryptCipher.doFinal(message);
texteCrypteStr= Base64.getEncoder().encodeToString(cipherText);
System.out.println("MESSAGE: "+cipherText);
//SIGNATURE DU MESSAGE
Signature signature = Signature.getInstance("SHA1withRSA","BC");
System.out.println("Initialisation de la signature");
signature.initSign(keyPri);
System.out.println("Hachage du message");
signature.update(cipherText);
System.out.println("Generation des bytes");
bytesign = signature.sign();
String texteSignStr= Base64.getEncoder().encodeToString(bytesign);
System.out.println("CLIENT SIGNATURE: "+texteSignStr);
Vector vecByte = new Vector();
vecByte.add(bytesign);
vecByte.add(cipherText);
dos.writeObject(vecByte);
received = dis.readUTF();
}
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
String concatMess="";
int k = 0;
while(k<vec.size()){
concatMess+=vec.get(k);
if(k+1<vec.size())
concatMess+="!";
k+=1;
}
System.out.println("VECTOR:"+concatMess);
byte[] message = concatMess.getBytes(StandardCharsets.UTF_8);
cipherText = encryptCipher.doFinal(message);
System.out.println("MESSAGE byte: "+cipherText);
cipherTextString = Base64.getEncoder().encodeToString(cipherText);
感谢这个解决方案,我得到了正确的信息。
感谢您的建议和解释。我找到了解决方案,这要归功于: 我必须在base64中对加密消息的结果进行编码,并在解密之前对其进行解码 客户端:
private void payActionPerformed(java.awt.event.ActionEvent evt) {
DataInputStream dis = new DataInputStream(s.getInputStream());
ObjectOutputStream dos = new ObjectOutputStream(s.getOutputStream());
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] message = concatMess.getBytes("UTF-8");
cipherText = encryptCipher.doFinal(message);
texteCrypteStr= Base64.getEncoder().encodeToString(cipherText);
System.out.println("MESSAGE: "+cipherText);
//SIGNATURE DU MESSAGE
Signature signature = Signature.getInstance("SHA1withRSA","BC");
System.out.println("Initialisation de la signature");
signature.initSign(keyPri);
System.out.println("Hachage du message");
signature.update(cipherText);
System.out.println("Generation des bytes");
bytesign = signature.sign();
String texteSignStr= Base64.getEncoder().encodeToString(bytesign);
System.out.println("CLIENT SIGNATURE: "+texteSignStr);
Vector vecByte = new Vector();
vecByte.add(bytesign);
vecByte.add(cipherText);
dos.writeObject(vecByte);
received = dis.readUTF();
}
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
String concatMess="";
int k = 0;
while(k<vec.size()){
concatMess+=vec.get(k);
if(k+1<vec.size())
concatMess+="!";
k+=1;
}
System.out.println("VECTOR:"+concatMess);
byte[] message = concatMess.getBytes(StandardCharsets.UTF_8);
cipherText = encryptCipher.doFinal(message);
System.out.println("MESSAGE byte: "+cipherText);
cipherTextString = Base64.getEncoder().encodeToString(cipherText);
感谢这个解决方案,我得到了正确的信息。
感谢您的建议和解释。您在编码和解码时指定了UTF-8(很好,但您可能希望使用StandardCharsets.UTF_8而不是“UTF-8”),但当您打印出消息时,它将以每个系统上的平台默认字符集打印,并且可能会被您查看结果的终端仿真器解释为不同的编码。您可能需要检查数据的散列,看看它是否真的不同。这有点混乱。核心问题是您正在尝试使用公钥解密。请记住:您使用私钥签名,然后使用收件人的公钥加密。收件人使用您的公钥进行验证,然后使用他的私钥进行解密。您和收件人之间不共享密钥对,这完全违背了非对称加密的目的。在您将该概念应用于此之后,您可以使用你应该对此做很多重要的改进。扔掉它,使用TLS。它比你的方案安全得多。如果你需要数字签名,请使用
SignedObject
@DavidConrad,这样问题就可能来自字符编码/解码?首先,我有一些困难,不要依赖默认值。始终s将完整的算法/模式/填充转换字符串指定为Cipher.getInstance()
。其次,我不确定您为什么在这里和那里使用“BC”提供程序,而不是在所有地方。除非您有充分的理由指定提供程序,否则不要指定提供程序。我看不到。您在编码和解码时指定UTF-8(很好,但您可能希望使用StandardCharsets.UTF_8而不是“UTF-8”),但当您打印出消息时,它将以每个系统上的平台默认字符集打印,并且可能会被您查看结果的终端仿真器解释为不同的编码。您可能需要检查数据的散列,看看它是否真的不同。这有点混乱。核心问题是您正在尝试使用公钥解密。请记住:您使用私钥进行签名,然后使用收件人的公钥进行加密。收件人使用您的公钥进行验证,然后使用他的私钥进行解密。您和收件人不共享密钥