我试图对客户端和服务器执行Diffie-Hellman密钥交换,但由于某种原因,当我解密发送到服务器的消息时。我得到以下例外:
Unable to decrypt ciphertext. -> Decryption error
javax.crypto.BadPaddingException: Decryption error
at java.base/sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:378)
at java.base/sun.security.rsa.RSAPadding.unpad(RSAPadding.java:290)
at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:359)
at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:392)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
at server.Server.decrypt(Server.java:354)
at server.Server.performDHKEX(Server.java:242)
at server.Server.<init>(Server.java:145)
at server.Driver.main(Driver.java:15)我知道我的加密/解密方法工作得很好,因为如果我这样做:decrypt(encrypt(bytes)),就不会抛出任何异常。有人知道为什么会这样吗?下面是我的客户端和服务器代码。
蒂娅!
客户端
private SecretKey performDHKEX()
{
SecretKey sharedKey = null;
try
{
// Send a message telling the server to get ready for a DH-KEX.
outputStream.writeObject("DO_DH_KEX");
KeyAgreement ecdhKex = KeyAgreement.getInstance("ECDH");
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
KeyPair keyPair = gen.genKeyPair();
// Send the Client's Public Value.
byte[] cText = encrypt(keyPair.getPublic().getEncoded());
decrypt(encrypt(keyPair.getPublic().getEncoded()));
byte[] sign = sign(keyPair.getPublic().getEncoded());
outputStream.writeObject(cText);
outputStream.writeObject(X509_CERTIFICATE);
// Start the exchange with Private Key.
ecdhKex.init(keyPair.getPrivate());
/* Wait for the response from the Server, then decrypt and load the
public value the Server sent. */
byte[][] recvCipherText = (byte[][]) inputStream.readObject();
X509Certificate serverCert = (X509Certificate) inputStream
.readObject();
byte[] plainText = decrypt(recvCipherText[0]);
// If the signature verifies, build a keyspec from the public value.
if (verify(recvCipherText[1], plainText, serverCert))
{
// Create a new PublicKey from the Server's Public Value.
PublicKey pub = KeyFactory.getInstance("EC")
.generatePublic(new X509EncodedKeySpec(plainText));
// Perform the last step of the KEX and create a new SecretKey.
ecdhKex.doPhase(pub, true);
// Use the first 16 bytes of the generate secret for a key.
sharedKey = new SecretKeySpec(Arrays.copyOfRange(ecdhKex
.generateSecret(), 0, 16), "AES");
}
else
System.err.println("Error verifying signature.");
} catch (IOException | ClassNotFoundException | IllegalStateException |
InvalidKeyException | NoSuchAlgorithmException |
InvalidKeySpecException ex)
{
System.err.println("Error during DH-KEX -> " + ex.getMessage());
}
System.out.println(Base64.getEncoder().encodeToString(sharedKey.getEncoded()));
return sharedKey;
}服务器
private SecretKey performDHKEX()
{
SecretKey sharedKey = null;
try
{
KeyAgreement ecdhKex = KeyAgreement.getInstance("ECDH");
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
KeyPair keyPair = gen.genKeyPair();
byte[] recvMessage = (byte[]) inputStream.readObject();
X509Certificate clientCert = (X509Certificate) inputStream
.readObject();
// Decrypt the ciphertext.
byte[] plainText = decrypt(recvMessage); // EXCEPTION THROWN HERE
// If the signature and certificate verify, complete the KEX.
if (verify(recvMessage, plainText, clientCert))
{
System.out.println("inside verify");
// Send the Server's Public Value.
byte[] sign = sign(keyPair.getPublic().getEncoded());
byte[] cText = encrypt(keyPair.getPublic().getEncoded());
byte[][] sendArray = {cText, sign};
outputStream.writeObject(sendArray);
outputStream.writeObject(X509_CERTIFICATE);
PublicKey pub = KeyFactory.getInstance("EC")
.generatePublic(new X509EncodedKeySpec(plainText));
// Start the exchange with the server's Private Value and then
// doPhase with the Client's public Value.
ecdhKex.init(keyPair.getPrivate());
ecdhKex.doPhase(pub, true);
// Use the first 16 bytes of the generate secret for a key.
sharedKey = new SecretKeySpec(Arrays.copyOfRange(ecdhKex
.generateSecret(), 0, 16), "AES");
}
} catch (IOException | ClassNotFoundException | IllegalStateException |
InvalidKeyException | NoSuchAlgorithmException |
InvalidKeySpecException ex)
{
System.err.println("Error during DH-KEX -> " + ex.getMessage());
}
System.out.println(Base64.getEncoder().encodeToString(sharedKey.getEncoded()));
return sharedKey;
}加密
private byte[] encrypt(byte[] message)
{
byte[] cipherText = null;
try
{
rsaCipher.init(Cipher.ENCRYPT_MODE, PRIV_KEY);
cipherText = rsaCipher.doFinal(message);
} catch (InvalidKeyException | BadPaddingException |
IllegalBlockSizeException ex)
{
System.err.println("Error encrypting message. -> " + ex
.getMessage());
ex.printStackTrace();
}
return cipherText;
}解密
private byte[] decrypt(byte[] cipherText)
{
try
{
rsaCipher.init(Cipher.DECRYPT_MODE, PUB_KEY);
return rsaCipher.doFinal(cipherText);
} catch (InvalidKeyException | IllegalBlockSizeException |
BadPaddingException ex)
{
System.err.println("Unable to decrypt ciphertext. -> " + ex
.getMessage());
ex.printStackTrace();
}
return null;
}为了澄清,RSA密码是RSA/ECB/PKCS1Padd,PRIV_KEY/PUB_KEY是从KeyTool生成的
发布于 2021-05-05 21:59:11
当使用错误的密钥执行解密时,BadPaddingExceptions是非常常见的失败模式。
服务器必须使用客户端的公钥进行解码,同时使用自己的密钥进行编码。
类似地,客户端必须使用服务器的公钥进行解码,并使用自己的密钥进行编码。
您执行的测试表明,解码和编码使用的是本地公钥,而不是发件人的公钥。
https://stackoverflow.com/questions/67408246
复制相似问题