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

RSA公私钥加解密失败求助(Python+C+++OpenSSL场景)

问题:RSA跨语言加密解密失败(Python生成密钥,C++加密,OpenSSL解密报错)

背景

我有两个服务:服务B基于Python生成RSA公私钥,服务A基于C++获取服务B的公钥,对字符串加密后发送给服务B,由其用私钥解密。

Python密钥生成代码(服务B)

生成PKCS#1格式的PEM密钥文件:

def generateKeys(privateKeyFile, publicKeyFile, n=4096):
    (publicKey, privateKey) = rsa.newkeys(n)
    with open(publicKeyFile, 'wb') as p:
        p.write(publicKey.save_pkcs1('PEM'))
    with open(privateKeyFile, 'wb') as p:
        p.write(privateKey.save_pkcs1('PEM'))

C++加密代码(服务A)

int main()
{
    string devKey = "wh1plash";
    cout << devKey << "\n";
    string devKeyBase64 = base64_encode(devKey.c_str(), devKey.size());
    cout << "devKeyBase64 : " << devKeyBase64.c_str() << " size : " << devKeyBase64.size() << "\n";

    string publicKeyLocation = "/keys/publicKey.pem";
    FILE* file = fopen(publicKeyLocation.c_str(), "r");
    // Null Check here for file. Not shown here

    RSA *rsa = NULL;
    PEM_read_RSAPublicKey(file, &rsa, NULL, NULL);
    // Null Check for RSA. Not shown here

    EVP_PKEY* evpPkey = EVP_PKEY_new();
    EVP_PKEY_assign_RSA(evpPkey, rsa);
    // Null check for evpPkey. Not shown here

    fclose(file);
    
    // Create/initialize context
    EVP_PKEY_CTX* evpCtx;
    evpCtx = EVP_PKEY_CTX_new(evpPkey, NULL);
    EVP_PKEY_CTX_set_rsa_padding(evpCtx, RSA_PKCS1_PADDING);
    // Null check for evpCtx. Not shown here.

    EVP_PKEY_encrypt_init(evpCtx);

    // Encryption
    size_t ciphertextLen;
    EVP_PKEY_encrypt(evpCtx, NULL, &ciphertextLen, (const unsigned char*)devKeyBase64.c_str(), devKeyBase64.size());
    cout << " Cipher Text Len : " << ciphertextLen << "\n";
    unsigned char* ciphertext = (unsigned char*)OPENSSL_malloc(ciphertextLen);
    EVP_PKEY_encrypt(evpCtx, ciphertext, &ciphertextLen, (const unsigned char*)devKeyBase64.c_str(), devKeyBase64.size());

    string OutString;
    cout << " Cipher Text : " << ciphertext << "\n";
    OutString.assign((char*)ciphertext, ciphertextLen);

    cout << "Encrypted String: ||" << OutString.c_str() << "||";
    cout << "\nDone\n";

    // Release memory
    EVP_PKEY_CTX_free(evpCtx);
    // EVP_PKEY_free(evpPkey);
    // OPENSSL_free(ciphertext);
    return 0;
}

问题现象

加密后输出非ASCII密文,但使用OpenSSL命令解密时失败,即使设置无填充也只能得到乱码,无法还原原始Base64字符串。

解密命令及错误信息

$ openssl pkeyutl -decrypt -in file.enc -inkey privateKey.pem -out out.txt -pkeyopt rsa_padding_mode:pkcs1
Public Key operation error
140501996771216:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:rsa_pk1.c:301:
140501996771216:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:rsa_eay.c:643:

问题排查与解决

1. 密文的编码与存储问题

C++代码中直接将二进制密文转成std::string并输出,会因为二进制包含不可打印字符或\0截断符,导致保存到文件的密文和实际加密结果不一致(比如cout << ciphertext会在遇到\0时停止输出),这是解密失败的核心原因。

解决方法:

  • 加密后对二进制密文做Base64编码,再保存或传输。修改C++代码示例:
    // 加密后添加Base64编码步骤
    string ciphertextBase64 = base64_encode((const char*)ciphertext, ciphertextLen);
    cout << "Encrypted Base64 String: ||" << ciphertextBase64 << "||\n";
    // 将ciphertextBase64写入文件,而不是原始二进制密文
    
  • 解密时先解码Base64到二进制,再执行OpenSSL解密:
    # 先将Base64密文解码为二进制文件
    base64 -d file.enc.b64 > file.enc
    # 再执行解密命令
    openssl pkeyutl -decrypt -in file.enc -inkey privateKey.pem -out out.txt -pkeyopt rsa_padding_mode:pkcs1
    

2. 内存释放隐患

代码中注释掉了EVP_PKEY_free(evpPkey)和OPENSSL_free(ciphertext),EVP_PKEY_assign_RSA会转移RSA对象的所有权,EVP_PKEY_free会自动释放RSA,建议取消注释这两行,避免内存泄漏影响后续操作。

验证步骤

  1. 用修改后的C++代码生成Base64编码的密文,保存到file.enc.b64
  2. 执行Base64解码得到二进制密文文件file.enc
  3. 用OpenSSL命令解密,查看out.txt内容是否为原始Base64字符串d2gxbGxhc2g=
  4. 对out.txt内容做Base64解码,验证是否得到原始字符串wh1plash

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 12:02:51