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,建议取消注释这两行,避免内存泄漏影响后续操作。
验证步骤
- 用修改后的C++代码生成Base64编码的密文,保存到
file.enc.b64 - 执行Base64解码得到二进制密文文件
file.enc - 用OpenSSL命令解密,查看
out.txt内容是否为原始Base64字符串d2gxbGxhc2g= - 对
out.txt内容做Base64解码,验证是否得到原始字符串wh1plash
内容的提问来源于stack exchange,提问作者whiplash
相关产品推荐
相关产品推荐

