c++必须依赖openssl等成熟密码库实现rsa加解密,不可手写;应使用rsa_generate_key_ex生成2048位以上密钥,配合pkcs#1或oaep填充,严格检查返回值、缓冲区大小及密钥格式,避免内存泄漏与填充错配。

用OpenSSL实现RSA加解密,别自己手写密码学逻辑
直接上结论:C++标准库不提供RSA支持,必须依赖成熟密码库;OpenSSL是最常用、文档最全、生产环境验证过的选项。自己实现RSA密钥生成、填充(如PKCS#1 v1.5或OAEP)、模幂运算极易出错,且存在侧信道风险,不建议尝试。
实际开发中,你真正要做的只是正确调用openssl的C API,并严格处理内存和错误码。以下基于OpenSSL 3.x(推荐)或1.1.1系列,注意两者API有差异,本文以1.1.1为主(兼容性更广)。
生成密钥对:用RSA_generate_key_ex而非已废弃的RSA_generate_key
旧版RSA_generate_key在OpenSSL 1.1.0+已被标记为deprecated,新代码必须用RSA_generate_key_ex配合BIGNUM和BN_CTX。
关键点:
-
RSA结构体需用RSA_new()分配,完成后必须RSA_free(),否则内存泄漏 - 公钥指数通常用
BN_new()设为65537(即0x10001),不要用3——安全性不足 - 密钥长度至少2048位;1024位已不安全,部分系统(如macOS 12+)会拒绝加载
- 生成后需用
PEM_write_RSAPrivateKey和PEM_write_RSAPublicKey导出为文件,或用i2d_RSAPrivateKey转为二进制缓冲区
加密时必须用RSA_public_encrypt并指定填充模式
常见错误是传入明文长度超过限制却没检查——RSA加密明文长度上限 = 密钥长度(字节)− 填充开销。例如2048位RSA(256字节),PKCS#1 v1.5最多加密256 − 11 = 245字节;OAEP更少(约214字节)。超长会直接返回−1。
实操要点:
- 始终检查返回值:成功返回密文长度(≥0),失败返回−1,必须调用
ERR_print_errors_fp(stderr)查错 - 填充方式选
RSA_PKCS1_OAEP_PADDING(更安全)或RSA_PKCS1_PADDING(兼容老系统),不要用RSA_NO_PADDING(裸RSA,极度危险) - 输入明文必须是
unsigned char*,不能是std::string.c_str()后直接传——要确保末尾无意外\0截断;建议显式传str.length()和const_cast<unsigned char>(...)</unsigned> - 输出缓冲区大小必须预分配为
RSA_size(rsa)(即密钥字节数),小了会崩溃
解密失败?先确认私钥加载方式和错误码
最常踩的坑是私钥格式不匹配:RSA_private_decrypt只接受PKCS#1格式私钥(BEGIN RSA PRIVATE KEY),而PEM_read_RSAPrivateKey才能正确加载;若用PEM_read_PrivateKey(通用接口),它可能返回EVP_PKEY,需额外EVP_PKEY_get1_RSA提取,容易漏掉错误检查。
调试建议:
- 用
openssl rsa -in key.pem -text -noout确认私钥可被OpenSSL命令行读取 - 解密前检查
RSA_check_key(rsa)是否返回1,否则私钥损坏或不完整 - 解密返回−1时,90%是填充错误(比如加密用OAEP但解密用PKCS#1)或密钥类型不匹配(公钥加密/私钥解密必须配对)
- 输出明文缓冲区大小也要设为
RSA_size(rsa),解密后真实长度由返回值给出,不可直接当C字符串用——需手动加\0或用std::vector截取
真正的难点不在函数调用本身,而在密钥生命周期管理、错误分支覆盖、以及填充模式与密钥格式的隐式耦合。哪怕只写一个demo,也建议把RSA*封装进RAII类,避免RSA_free遗漏;所有OpenSSL函数调用后都应检查返回值,而不是只在“关键处”判断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











