openssl c++封装无官方api,需手动管理bio/rsa生命周期;密钥加载须用pem_read_bio_*配对bio_new_mem_buf();rsa加密明文上限为rsa_size(rsa)-11;密钥写入前须chmod 600防泄露;错误队列需循环err_get_error()清空。

OpenSSL 的 C++ 封装本身不存在官方 API,所谓“C++ 使用 OpenSSL”实际是用 C 风格的 OpenSSL 库(libssl 和 libcrypto)在 C++ 环境中调用,需手动管理资源、处理错误、规避裸指针误释放——这不是语法问题,而是内存与生命周期问题。
如何正确加载 RSA 密钥并避免 SEGFAULT 或 nullptr 解引用
OpenSSL 1.1.1+ 后,RSA 结构体被 opaque 化,不能直接访问成员;密钥加载必须通过 PEM_read_bio_RSAPrivateKey / PEM_read_bio_RSAPublicKey,且必须配对使用 BIO 生命周期管理。
-
BIO*必须用BIO_new_mem_buf()创建,传入 PEM 字符串地址和长度(不能传std::string::c_str()后不指定长度,否则遇到 \0 会截断) - 私钥加载失败常见原因是密码不匹配或格式非 PKCS#1(如用了 PKCS#8),此时返回
nullptr,但不会报错——必须用ERR_get_error()检查 - 成功加载后,
RSA*对象必须用RSA_free()释放,不能用delete;若封装成 RAII 类,析构函数里必须判空再调RSA_free
为什么 RSA_public_encrypt() 返回 -1 且 ERR_get_error() 显示 rsa routines:RSA_padding_add_PKCS1_type_2:data too large for key size
RSA 加密明文长度受限于密钥长度和填充方式。PKCS#1 v1.5 填充固定占用至少 11 字节,因此最大明文长度 = RSA_size(rsa) - 11。例如 2048 位密钥,RSA_size() 返回 256 字节,最多加密 245 字节。
- 不要试图分块调用
RSA_public_encrypt:它不是流式接口,每次调用都需完整填充,无法接力 - 真实场景应改用混合加密:用 RSA 加密一个随机 AES 密钥,再用 AES 加密原始数据
- 若坚持纯 RSA,必须提前
if (plaintext_len > RSA_size(rsa) - 11) { /* reject */ },否则返回 -1 且输出缓冲区内容未定义
如何安全生成密钥并写入 PEM 文件(避免权限泄露)
OpenSSL 不自动设置文件权限,PEM_write_RSAPrivateKey 直接写磁盘可能导致私钥被其他用户读取。
立即学习“C++免费学习笔记(深入)”;
- 生成密钥必须用
RSA_generate_key_ex()(OpenSSL 1.1.0+ 推荐),而非已废弃的RSA_generate_key() - 写私钥前先用
umask(077)临时收紧权限,或写入/tmp后用chmod 600显式设置(Windows 下忽略) - 写入时若需密码保护,
cb参数不能为nullptr;推荐用PEM_write_enc_RSAPrivateKey并传入EVP_des_ede3_cbc()等算法,密码由回调函数提供 - 公钥可无密码导出,但务必确认
PEM_write_RSAPublicKey(写 PKCS#1 格式)还是PEM_write_PUBKEY(写 SubjectPublicKeyInfo,兼容性更好)
最易被忽略的是错误队列残留:OpenSSL 错误是线程局部的,但每个函数调用可能压入多条错误。一次 ERR_get_error() 只取一条,连续调用直到返回 0 才清空。调试时若只查一次,会漏掉根本原因。










