You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt Windows平台下RSA私钥加密实现问询(PEM格式密钥)

在Qt Windows环境下实现RSA私钥加密、公钥解密(PEM格式密钥)

我之前在Qt Windows环境下正好实现过这个需求,完全清楚你要的是私钥加密、公钥解密的特定场景(不是签名也不是常规的公钥加密流程),下面给你一套可落地的方案:

核心思路

Qt本身的QSslKey可以方便加载PEM格式的RSA密钥,但没有直接提供私钥加密的API,所以我们可以借助Qt底层依赖的OpenSSL原生API来实现——毕竟Qt的SSL模块本身就是基于OpenSSL构建的,这样既不用引入额外第三方库,也能保证兼容性。

准备工作

  1. 配置Qt项目依赖:
    • 在项目的.pro文件中添加QT += network(QSslKey属于network模块)
    • 如果是MinGW编译器,追加LIBS += -lcrypto -lssl;如果是MSVC,需要将OpenSSL的libcrypto.lib和libssl.lib路径加入项目配置
  2. 准备OpenSSL动态库:
    • 根据你的Qt版本匹配对应的OpenSSL版本(比如Qt 5.15对应OpenSSL 1.1.x),下载libcrypto-*.dll和libssl-*.dll,将它们放到程序运行目录或者系统环境变量路径中,否则程序启动会报错找不到依赖。

代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:39:08