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

如何基于OpenSSL实现DER编码RSA公钥加密并完成Python到C++移植?

使用OpenSSL实现RSA公钥加密(对应Python Crypto逻辑)

刚好我之前也做过类似的Python到C++的OpenSSL移植,结合你的需求,咱们一步步对应实现逻辑:

1. 导入服务器返回的二进制公钥

你的Python代码里key_bin是服务器发的二进制公钥串,大概率是ASN.1 DER格式(Python的importKey默认支持DER/PEM)。OpenSSL里我们需要分两种情况解析:如果是标准X.509公钥格式(更常见)用d2i_PUBKEY,如果是原始RSAPublicKey格式用d2i_RSAPublicKey,下面是兼容两种格式的导入函数:

#include <openssl/rsa.h>
#include <openssl/err.h>
#include <vector>
#include <cstring>

RSA* import_rsa_public_key(const std::vector<unsigned char>& key_bin) {
    const unsigned char* ptr = key_bin.data();
    // 先尝试解析X.509标准公钥格式
    EVP_PKEY* pkey = d2i_PUBKEY(nullptr, &ptr, key_bin.size());
    if (pkey) {
        RSA* rsa = EVP_PKEY_get1_RSA(pkey);
        EVP_PKEY_free(pkey);
        return rsa;
    }
    // 失败则尝试原始RSAPublicKey格式
    ptr = key_bin.data();
    RSA* rsa = d2i_RSAPublicKey(nullptr, &ptr, key_bin.size());
    if (!rsa) {
        ERR_print_errors_fp(stderr);
        return nullptr;
    }
    return rsa;
}

2. 处理RSA填充(核心兼容点)

你的Python代码里有自定义的add_rsa_padding,这是最容易出问题的地方,必须保证C++端的填充逻辑和Python完全一致:

情况1:用OpenSSL内置填充(比如PKCS#1 v1.5)

如果你的add_rsa_padding实现的是标准PKCS#1 v1.5,那直接用OpenSSL内置的填充即可,不用手动处理:

std::vector<unsigned char> rsa_encrypt_with_padding(RSA* rsa, const std::vector<unsigned char>& data) {
    int rsa_key_len = RSA_size(rsa);
    std::vector<unsigned char> encrypted(rsa_key_len);
    
    // RSA_PKCS1_PADDING对应Python Crypto的默认加密填充
    int ret = RSA_public_encrypt(data.size(), data.data(), encrypted.data(), rsa, RSA_PKCS1_PADDING);
    if (ret == -1) {
        ERR_print_errors_fp(stderr);
        return {};
    }
    encrypted.resize(ret); // 截取实际加密有效长度
    return encrypted;
}

情况2:自定义填充逻辑

如果你的add_rsa_padding是自定义规则,那先手动复刻填充逻辑,再用无填充模式加密:

// 完全复刻你Python里的add_rsa_padding逻辑
std::vector<unsigned char> add_rsa_padding(const std::vector<unsigned char>& data, int rsa_key_len) {
    std::vector<unsigned char> padded(rsa_key_len);
    // 这里写你Python里的填充规则,比如示例的PKCS#1 v1.5模拟:
    padded[0] = 0x00;
    padded[1] = 0x02; // 加密块标识
    // 填充随机非零字节(和Python逻辑一致)
    for (int i = 2; i < rsa_key_len - data.size() - 1; ++i) {
        padded[i] = rand() % 255 + 1; // 保证非零
    }
    padded[rsa_key_len - data.size() - 1] = 0x00;
    // 复制原始数据到末尾
    std::memcpy(&padded[rsa_key_len - data.size()], data.data(), data.size());
    return padded;
}

// 无填充模式加密
std::vector<unsigned char> rsa_encrypt_no_padding(RSA* rsa, const std::vector<unsigned char>& padded_data) {
    int rsa_key_len = RSA_size(rsa);
    if (padded_data.size() != rsa_key_len) {
        fprintf(stderr, "Padded data length mismatch!\n");
        return {};
    }
    std::vector<unsigned char> encrypted(rsa_key_len);
    int ret = RSA_public_encrypt(rsa_key_len, padded_data.data(), encrypted.data(), rsa, RSA_NO_PADDING);
    if (ret == -1) {
        ERR_print_errors_fp(stderr);
        return {};
    }
    return encrypted;
}

3. 完整流程示例(对应你的Python代码)

把所有步骤串起来,和你的Python逻辑一一对应:

int main() {
    // 初始化OpenSSL错误处理
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    // 1. 获取服务器公钥(对应你的get_server_key())
    std::vector<unsigned char> key_bin = get_server_key();

    // 2. 导入公钥
    RSA* rsa = import_rsa_public_key(key_bin);
    if (!rsa) {
        fprintf(stderr, "Failed to load RSA public key!\n");
        return 1;
    }

    // 3. 准备要加密的原始数据
    std::vector<unsigned char> data = {...}; // 你的业务数据

    // 4. 加密(二选一,根据填充方式)
    std::vector<unsigned char> encrypted_data;
    // 用内置填充的情况:
    encrypted_data = rsa_encrypt_with_padding(rsa, data);
    // 用自定义填充的情况:
    // int rsa_len = RSA_size(rsa);
    // auto padded = add_rsa_padding(data, rsa_len);
    // encrypted_data = rsa_encrypt_no_padding(rsa, padded);

    // 5. 发送加密后的数据(对应你的send_data())
    send_data(encrypted_data);

    // 清理OpenSSL资源,避免内存泄漏
    RSA_free(rsa);
    EVP_cleanup();
    ERR_free_strings();

    return 0;
}

关键注意点

  • 密钥格式排查:如果公钥导入失败,把key_bin转成十六进制打印,对比Python里的格式——如果包含-----BEGIN PUBLIC KEY-----这类字符串,那是PEM格式,需要用PEM_read_bio_RSAPublicKey解析。
  • 填充一致性:这是加密后服务器能否解密的核心!一定要逐行对比Python和C++的填充逻辑,比如填充字节的规则、长度计算。
  • 资源清理:OpenSSL的结构体(RSA*、EVP_PKEY*)必须手动释放,否则会有内存泄漏。

内容的提问来源于stack exchange,提问作者William Chapa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:20:58