OpenSSL 1.1.1中ED448公钥DER编码失败问题求助
解决ED448公钥编码失败的问题
你踩了OpenSSL 1.1.1对Ed448支持的一个小坑:这个版本里,Ed448(以及同系列的Ed25519)密钥并不兼容传统的i2d_PublicKey接口。i2d_PublicKey是为基于X.509 SubjectPublicKeyInfo结构的DER/PEM编码设计的,但早期OpenSSL对Ed448的支持只实现了原始密钥字节的读写能力,没有适配标准的ASN.1编码逻辑,所以才会抛出“不支持的公钥类型”错误。
更贴合你需求的方案:直接提取原始公钥字节
既然你想要“小巧可移植的字节数组”,那Ed448的原始公钥本身就是最优解——它固定是56字节(对应448位),没有额外的ASN.1包装,体积更小、解析更简单。你可以用EVP_PKEY_get_raw_public_key接口替代i2d_PublicKey,修改后的代码如下:
std::vector<std::vector<uint8_t>> vecs; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED448, NULL); if (!pctx) { ERR_print_errors_fp(stderr); // 这里可以加错误处理逻辑,比如return或者抛出异常 return; } if (EVP_PKEY_keygen_init(pctx) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(pctx); return; } EVP_PKEY* pkey = nullptr; if (EVP_PKEY_keygen(pctx, &pkey) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(pctx); return; } EVP_PKEY_CTX_free(pctx); // 获取原始公钥长度,Ed448固定为56字节 size_t pub_key_len = EVP_PKEY_get_size(pkey); std::vector<uint8_t> pub_key(pub_key_len); // 提取原始公钥字节到vector中 if (EVP_PKEY_get_raw_public_key(pkey, pub_key.data(), &pub_key_len) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_free(pkey); return; } vecs.push_back(std::move(pub_key)); EVP_PKEY_free(pkey);
如果必须用DER编码怎么办?
如果你的场景硬性要求DER格式的公钥(比如要嵌入X.509证书),那OpenSSL 1.1.1做不到——Ed448的X.509 SubjectPublicKeyInfo编码支持是在OpenSSL 3.0及以后版本才完善的。你需要升级到Debian stable版本中的OpenSSL 3.0(或更高),升级后i2d_PublicKey就能正常处理Ed448密钥了。
几个关键提醒
- Ed448的原始公钥长度固定为56字节,私钥是57字节(多一个公钥字节用于性能优化),你也可以直接写死这个长度来分配缓冲区,避免调用
EVP_PKEY_get_size。 - 一定要检查OpenSSL所有API的返回值(大部分接口返回<=0表示失败),不然很容易出现空指针或者内存越界的问题。
内容的提问来源于stack exchange,提问作者Cyclic3
相关产品推荐
相关产品推荐

