Qt Windows平台下RSA私钥加密实现问询(PEM格式密钥)
在Qt Windows环境下实现RSA私钥加密、公钥解密(PEM格式密钥)
我之前在Qt Windows环境下正好实现过这个需求,完全清楚你要的是私钥加密、公钥解密的特定场景(不是签名也不是常规的公钥加密流程),下面给你一套可落地的方案:
核心思路
Qt本身的QSslKey可以方便加载PEM格式的RSA密钥,但没有直接提供私钥加密的API,所以我们可以借助Qt底层依赖的OpenSSL原生API来实现——毕竟Qt的SSL模块本身就是基于OpenSSL构建的,这样既不用引入额外第三方库,也能保证兼容性。
准备工作
- 配置Qt项目依赖:
- 在项目的
.pro文件中添加QT += network(QSslKey属于network模块) - 如果是MinGW编译器,追加
LIBS += -lcrypto -lssl;如果是MSVC,需要将OpenSSL的libcrypto.lib和libssl.lib路径加入项目配置
- 在项目的
- 准备OpenSSL动态库:
- 根据你的Qt版本匹配对应的OpenSSL版本(比如Qt 5.15对应OpenSSL 1.1.x),下载
libcrypto-*.dll和libssl-*.dll,将它们放到程序运行目录或者系统环境变量路径中,否则程序启动会报错找不到依赖。
- 根据你的Qt版本匹配对应的OpenSSL版本(比如Qt 5.15对应OpenSSL 1.1.x),下载
代码实现
1. 加载PEM格式密钥
首先用QSslKey读取本地的PEM密钥文件:
// 加载RSA私钥(PEM格式) QFile privateKeyFile("private_key.pem"); if (!privateKeyFile.open(QIODevice::ReadOnly)) { qDebug() << "Failed to open private key file!"; return; } QSslKey privateKey(privateKeyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); privateKeyFile.close(); // 加载RSA公钥(PEM格式) QFile publicKeyFile("public_key.pem"); if (!publicKeyFile.open(QIODevice::ReadOnly)) { qDebug() << "Failed to open public key file!"; return; } QSslKey publicKey(publicKeyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PublicKey); publicKeyFile.close();
2. 私钥加密函数
通过QSslKey拿到OpenSSL的EVP_PKEY句柄,调用OpenSSL的加密API实现私钥加密:
#include <openssl/evp.h> #include <openssl/rsa.h> QByteArray rsaPrivateEncrypt(const QByteArray& plainText, const QSslKey& privateKey) { // 校验密钥类型 if (privateKey.type() != QSsl::PrivateKey || privateKey.algorithm() != QSsl::Rsa) { qDebug() << "Invalid RSA private key!"; return QByteArray(); } EVP_PKEY* pkey = static_cast<EVP_PKEY*>(privateKey.handle()); EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr); if (!ctx) { qDebug() << "Failed to create EVP_PKEY_CTX!"; return QByteArray(); } // 初始化加密上下文 if (EVP_PKEY_encrypt_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to init encrypt context!"; return QByteArray(); } // 设置PKCS1填充模式(和公钥解密对应) if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to set RSA padding!"; return QByteArray(); } // 先获取加密后的数据长度 size_t outLen = 0; if (EVP_PKEY_encrypt(ctx, nullptr, &outLen, reinterpret_cast<const unsigned char*>(plainText.constData()), plainText.size()) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to get encrypt output length!"; return QByteArray(); } // 分配内存并执行加密 QByteArray cipherText(outLen, 0); if (EVP_PKEY_encrypt(ctx, reinterpret_cast<unsigned char*>(cipherText.data()), &outLen, reinterpret_cast<const unsigned char*>(plainText.constData()), plainText.size()) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to encrypt data!"; return QByteArray(); } cipherText.resize(outLen); EVP_PKEY_CTX_free(ctx); return cipherText; }
3. 公钥解密函数
同样借助OpenSSL API实现公钥解密:
QByteArray rsaPublicDecrypt(const QByteArray& cipherText, const QSslKey& publicKey) { // 校验密钥类型 if (publicKey.type() != QSsl::PublicKey || publicKey.algorithm() != QSsl::Rsa) { qDebug() << "Invalid RSA public key!"; return QByteArray(); } EVP_PKEY* pkey = static_cast<EVP_PKEY*>(publicKey.handle()); EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr); if (!ctx) { qDebug() << "Failed to create EVP_PKEY_CTX!"; return QByteArray(); } // 初始化解密上下文 if (EVP_PKEY_decrypt_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to init decrypt context!"; return QByteArray(); } // 设置和加密一致的PKCS1填充模式 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to set RSA padding!"; return QByteArray(); } // 获取解密后的数据长度 size_t outLen = 0; if (EVP_PKEY_decrypt(ctx, nullptr, &outLen, reinterpret_cast<const unsigned char*>(cipherText.constData()), cipherText.size()) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to get decrypt output length!"; return QByteArray(); } // 分配内存并执行解密 QByteArray plainText(outLen, 0); if (EVP_PKEY_decrypt(ctx, reinterpret_cast<unsigned char*>(plainText.data()), &outLen, reinterpret_cast<const unsigned char*>(cipherText.constData()), cipherText.size()) <= 0) { EVP_PKEY_CTX_free(ctx); qDebug() << "Failed to decrypt data!"; return QByteArray(); } plainText.resize(outLen); EVP_PKEY_CTX_free(ctx); return plainText; }
4. 测试调用
int main(int argc, char *argv[]) { QApplication a(argc, argv); // (这里插入前面的密钥加载代码) QByteArray originalText = "This is a test message for RSA private encrypt -> public decrypt"; QByteArray encryptedData = rsaPrivateEncrypt(originalText, privateKey); QByteArray decryptedData = rsaPublicDecrypt(encryptedData, publicKey); qDebug() << "Original Text:" << originalText; qDebug() << "Decrypted Text:" << decryptedData; return a.exec(); }
注意事项
- 明文长度限制:RSA加密有长度限制,比如2048位密钥用PKCS1填充时,最大明文长度是
2048/8 - 11 = 245字节。如果你的明文超过这个长度,需要自己实现分段加密逻辑。 - 密钥格式:确保你的PEM密钥格式正确——私钥以
-----BEGIN RSA PRIVATE KEY-----开头,公钥以-----BEGIN PUBLIC KEY-----或-----BEGIN RSA PUBLIC KEY-----开头,QSslKey都能正确识别。 - OpenSSL版本兼容性:不同Qt版本依赖的OpenSSL版本不同,一定要匹配对应的版本,否则会出现链接或运行时错误。
内容的提问来源于stack exchange,提问作者psy21d
相关产品推荐
相关产品推荐

