直接用 fread 读出的 pem 公钥不能被 openssl 直接使用,因为其含 base64、头尾标记和换行符,需通过 bio + pem_read_bio_pubkey 解析;der 格式则须用 d2i_pubkey。

为什么直接用 fread 读出的公钥不能直接给 OpenSSL 用
因为 PEM 格式不是纯二进制密钥数据,而是 base64 编码后套了头尾标记(如 -----BEGIN PUBLIC KEY-----)的文本格式。你用 fread 拿到的是原始字节流,如果文件是 PEM 编码的,那里面混着 ASCII 换行符、破折号和 base64 字符——OpenSSL 的 d2i_PUBKEY_bio 或 PEM_read_bio_PUBKEY 会拒绝解析,报错类似 error:0909006C:PEM routines:get_name:no start line。
- 确认文件真实格式:用
file key.pub或head -n 3 key.pub看是否含-----BEGIN;如果是,则是 PEM,不是 DER - 别跳过换行符处理:PEM 解析器对行尾符敏感,Windows 的
\r\n在某些 OpenSSL 版本下可能触发ASN1_R_HEADER_TOO_LONG - 必须以
BIO方式加载:不能把 raw buffer 直接喂给d2i_PUBKEY,它只认 DER;PEM 必须走PEM_read_bio_PUBKEY或先用BIO_new_mem_buf包一层
用 BIO 正确加载 PEM 公钥的最小可行代码
核心是把内存里的 PEM 字符串转成 BIO,再交给 OpenSSL 解析。注意:字符串必须以 \0 结尾,且不能漏掉最后的换行(PEM 规范要求头尾行独立)。
#include <openssl>
#include <openssl>
#include <openssl><p>EVP_PKEY<em> load_pubkey_from_pem_buffer(const char</em> pem_data, size_t len) {
BIO* bio = BIO_new_mem_buf(pem_data, len);
if (!bio) return nullptr;</p>
<pre class="brush:php;toolbar:false;">EVP_PKEY* pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
BIO_free(bio);
return pkey; // 成功则返回非空,失败为 nullptr
}
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
pem_data必须是完整 PEM 字符串(含头尾标记和 base64 内容),不是 base64 子串 - 不要手动 base64 解码:OpenSSL 内部会处理,自己 decode 反而破坏格式
- 若从二进制文件读取,确保用
std::ifstream以std::ios::binary打开,但读完后要确认内容是 valid UTF-8/ASCII,且末尾有\0
如果文件其实是 DER(纯二进制),该用哪个函数
DER 是 ASN.1 编码的裸二进制,没 base64、没头尾标记。这时候不能用 PEM 函数,否则立刻报 no start line。得用 d2i_PUBKEY 系列,并确保输入 buffer 是完整 DER 编码字节流。
- 验证方式:
openssl asn1parse -i -in key.der能正常输出结构;或用xxd key.der | head看前几字节是否类似30 82 ...(ASN.1 SEQUENCE tag) - 正确调用:
EVP_PKEY* pkey = d2i_PUBKEY(nullptr, &der_ptr, der_len);,注意der_ptr是const unsigned char**类型,会自动前进 - 常见坑:传入
const unsigned char*但没取地址,导致编译通过但运行时崩溃;或der_len比实际小,截断导致ASN1_R_WRONG_TAG
加密场景下公钥格式选 PEM 还是 DER 更合适
PEM 更适合存储和传输,DER 更适合嵌入二进制协议或性能敏感路径。但关键不是“哪个好”,而是“别混用”——同一项目里如果一部分用 PEM 加载、另一部分误当 DER 解析,就会卡在格式校验上,错误信息又不直观。
- 调试建议:用
openssl pkey -in key.pem -pubout -outform der -out key.der相互转换,比手写解析逻辑快得多 - 生产环境强烈建议在文件头加 magic bytes 或扩展名标识格式(如
.pub.pem/.pub.der),避免运行时猜格式 - Android NDK 或嵌入式 OpenSSL 可能禁用 PEM 支持(
OPENSSL_NO_STDIO),此时只能用 DER +d2i_*,且需确保链接时包含libcrypto完整版
事情说清了就结束
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










