RSA 在 Qt/C++ 中使用 OpenSSL 加密并在 Java 中解密:Bad Padding Exception
RSA encrypt with OpenSSL in Qt/C++ and decrypt in Java: Bad Padding Exception
我正在尝试一个示例程序,我在 C++ Qt Framework 中使用 RSA public 密钥加密字符串(使用静态 linked OpenSSL C++ 库),并使用解密相同的密文javax.crypto 图书馆。我使用 PC 上的空闲端口通过套接字连接将此密文发送到本地主机。
代码如下:
我的Qt/C++代码:
main.cpp:
#include "cipher.h"
#include "assert.h"
#include "string.h"
#include <QApplication>
#include <QTcpSocket>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Cipher *cipher=new Cipher();
QTcpSocket *qts=new QTcpSocket();
qts->connectToHost("localhost",11111);
QByteArray message, enc_key,enc_message;
message="Elephant";
enc_message=cipher->encryptRSA(cipher->getPublicKey("publickey.pem"),message);
qDebug()<<message;
qDebug()<<enc_message;
if(qts->waitForConnected(300)){
qts->write(QString::fromStdString(enc_message.toStdString()).toUtf8().constData());
qts->write("\n");
qts->flush();
}
return a.exec();
}
对于 encryptRSA 函数,我使用了 VoidRealms 教程中的示例。这里是
GitHub link:
https://github.com/voidrealms/Qt-154
从上面的link我使用cipher.h
和cipher.cpp
没有任何变化。
Java代码:
package servertest;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.io.FileUtils;
public class ServerTest {
static int port=11111;
static ServerSocket ss;
static Socket s;
public static void main(String[] args) {
System.out.println("Server Started!");
try {
ss = new ServerSocket(port);
s=ss.accept();
InputStreamReader isr = new InputStreamReader(new BufferedInputStream(s.getInputStream()));
BufferedReader br = new BufferedReader(isr);
String str=br.readLine();
System.out.println("Received: "+str);
byte[] encrypted = str.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
PrivateKey privateKey = loadPrivateKey();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("Decrypted: "+new String(decrypted));
} catch (IOException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static PrivateKey loadPrivateKey() throws Exception {
String privateKeyPEM = FileUtils.readFileToString(new File("privatekey-pkcs8.pem"), StandardCharsets.UTF_8);
// strip off header, footer, newlines, whitespaces
privateKeyPEM = privateKeyPEM
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replace("-----BEGIN RSA PRIVATE KEY-----", "")
.replace("-----END RSA PRIVATE KEY-----", "")
.replaceAll("\s", "");
//System.out.println(privateKeyPEM);
// decode to get the binary DER representation
byte[] privateKeyDER = Base64.getDecoder().decode(privateKeyPEM.getBytes("UTF-8"));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyDER));
return privateKey;
}
}
另外,我使用标准的 OpenSSL 命令生成了这些密钥。我尝试使用具有不同位长度的不同密钥,但我得到了相同的错误。我已将 privatekey.pem
转换为 PKCS8 ( privatekey-pkcs8.pem
)。为了生成和使用密钥,我遵循了下面的 link:
https://adangel.org/2016/08/29/openssl-rsa-java/
问题:
我在 Java 中得到 javax.crypto.BadPaddingException: Decryption error
。我做错了什么?
我已经尝试过的东西
- 我是加密新手,我不知道是否应该将此密文编码为 base64 或 hex 之类的东西,当我尝试这样做时,Java 抱怨密文比允许的最大位数长。
- 在 qts->write() 阶段,我尝试了几种数据类型和格式之间的转换,包括 const char*、char[]、QByteArray、toUtf8().toconstData()、std::string,转换为QString 同时使用 QString::fromUtf8() 和 QString::fromLocal8bit()。我应该尝试 Utf16 和 Latin1 吗?
请帮我解决这个问题。
好的,我在发布后 20 分钟内解决了这个问题,方法是将密文转换为 Base64 并通过套接字传递,当然,在接收端,我需要将其解码回字节。
以前我尝试这样做时,忘记将 Base64 文本解码回字节。对不起,如果我浪费了别人的时间。
我正在尝试一个示例程序,我在 C++ Qt Framework 中使用 RSA public 密钥加密字符串(使用静态 linked OpenSSL C++ 库),并使用解密相同的密文javax.crypto 图书馆。我使用 PC 上的空闲端口通过套接字连接将此密文发送到本地主机。
代码如下:
我的Qt/C++代码:
main.cpp:
#include "cipher.h"
#include "assert.h"
#include "string.h"
#include <QApplication>
#include <QTcpSocket>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Cipher *cipher=new Cipher();
QTcpSocket *qts=new QTcpSocket();
qts->connectToHost("localhost",11111);
QByteArray message, enc_key,enc_message;
message="Elephant";
enc_message=cipher->encryptRSA(cipher->getPublicKey("publickey.pem"),message);
qDebug()<<message;
qDebug()<<enc_message;
if(qts->waitForConnected(300)){
qts->write(QString::fromStdString(enc_message.toStdString()).toUtf8().constData());
qts->write("\n");
qts->flush();
}
return a.exec();
}
对于 encryptRSA 函数,我使用了 VoidRealms 教程中的示例。这里是 GitHub link: https://github.com/voidrealms/Qt-154
从上面的link我使用cipher.h
和cipher.cpp
没有任何变化。
Java代码:
package servertest;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.io.FileUtils;
public class ServerTest {
static int port=11111;
static ServerSocket ss;
static Socket s;
public static void main(String[] args) {
System.out.println("Server Started!");
try {
ss = new ServerSocket(port);
s=ss.accept();
InputStreamReader isr = new InputStreamReader(new BufferedInputStream(s.getInputStream()));
BufferedReader br = new BufferedReader(isr);
String str=br.readLine();
System.out.println("Received: "+str);
byte[] encrypted = str.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
PrivateKey privateKey = loadPrivateKey();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("Decrypted: "+new String(decrypted));
} catch (IOException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static PrivateKey loadPrivateKey() throws Exception {
String privateKeyPEM = FileUtils.readFileToString(new File("privatekey-pkcs8.pem"), StandardCharsets.UTF_8);
// strip off header, footer, newlines, whitespaces
privateKeyPEM = privateKeyPEM
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replace("-----BEGIN RSA PRIVATE KEY-----", "")
.replace("-----END RSA PRIVATE KEY-----", "")
.replaceAll("\s", "");
//System.out.println(privateKeyPEM);
// decode to get the binary DER representation
byte[] privateKeyDER = Base64.getDecoder().decode(privateKeyPEM.getBytes("UTF-8"));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyDER));
return privateKey;
}
}
另外,我使用标准的 OpenSSL 命令生成了这些密钥。我尝试使用具有不同位长度的不同密钥,但我得到了相同的错误。我已将 privatekey.pem
转换为 PKCS8 ( privatekey-pkcs8.pem
)。为了生成和使用密钥,我遵循了下面的 link:
https://adangel.org/2016/08/29/openssl-rsa-java/
问题:
我在 Java 中得到 javax.crypto.BadPaddingException: Decryption error
。我做错了什么?
我已经尝试过的东西
- 我是加密新手,我不知道是否应该将此密文编码为 base64 或 hex 之类的东西,当我尝试这样做时,Java 抱怨密文比允许的最大位数长。
- 在 qts->write() 阶段,我尝试了几种数据类型和格式之间的转换,包括 const char*、char[]、QByteArray、toUtf8().toconstData()、std::string,转换为QString 同时使用 QString::fromUtf8() 和 QString::fromLocal8bit()。我应该尝试 Utf16 和 Latin1 吗?
请帮我解决这个问题。
好的,我在发布后 20 分钟内解决了这个问题,方法是将密文转换为 Base64 并通过套接字传递,当然,在接收端,我需要将其解码回字节。
以前我尝试这样做时,忘记将 Base64 文本解码回字节。对不起,如果我浪费了别人的时间。