如何将明文公钥转为DER格式?含OpenSSL及i2d_PUBKEY代码疑问
OpenSSL公钥转DER格式实操解答
问题1:如何通过OpenSSL将明文公钥转换为DER格式?
有两种常用实现方式:命令行工具快速转换,或C代码集成处理。
命令行方式
针对本地PEM格式公钥文件,直接执行openssl命令:
# RSA公钥转换 openssl rsa -in public_key.pem -pubin -outform der -out public_key.der # EC公钥转换(示例中的密钥为ECC类型) openssl ec -in public_key.pem -pubin -outform der -out public_key.der
参数说明:
-pubin:指定输入文件为公钥-outform der:设置输出格式为DER编码-out:指定输出文件路径
C代码基础方式
若需在程序中处理内存中的PEM公钥,核心步骤为解析PEM到密钥结构体,再序列化为DER格式,具体逻辑可参考问题2的完整示例。
问题2:用i2d_PUBKEY实现公钥转DER编码的具体操作
结合你提供的代码片段,以下是完整可运行的实现,包含PEM公钥解析、i2d_PUBKEY序列化及资源清理的完整流程:
#include <openssl/evp.h> #include <openssl/x509.h> #include <openssl/bio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // 模拟获取PEM格式公钥的函数 void get_pubkey_function(uint8_t **pubkey, size_t *len) { const char *pem_content = "-----BEGIN PUBLIC KEY-----\n" "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+GmnZ1UZqKfa81Yh0CG6huQPhYON\n" "Q0W7AE4whuX+oUOg+BewYSOLUwj5zfwRB3i7T07HoltPfAOYeHI57Oe7jA==\n" "-----END PUBLIC KEY-----"; *len = strlen(pem_content); *pubkey = (uint8_t *)malloc(*len + 1); if (*pubkey) { memcpy(*pubkey, pem_content, *len + 1); } } int main() { uint8_t *pem_pubkey = NULL; size_t pem_len = 0; EVP_PKEY *pkey = NULL; uint8_t *der_pubkey = NULL; int der_len = 0; // 获取PEM格式公钥 get_pubkey_function(&pem_pubkey, &pem_len); if (!pem_pubkey) { fprintf(stderr, "获取公钥失败\n"); return EXIT_FAILURE; } // 创建BIO对象读取内存中的PEM数据 BIO *bio = BIO_new_mem_buf(pem_pubkey, pem_len); if (!bio) { fprintf(stderr, "创建BIO缓冲区失败\n"); free(pem_pubkey); return EXIT_FAILURE; } // 解析PEM公钥到EVP_PKEY通用密钥结构体 pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); BIO_free(bio); free(pem_pubkey); if (!pkey) { fprintf(stderr, "解析PEM公钥失败\n"); return EXIT_FAILURE; } // 第一步:调用i2d_PUBKEY获取DER数据长度(传入NULL指针) der_len = i2d_PUBKEY(pkey, NULL); if (der_len <= 0) { fprintf(stderr, "计算DER数据长度失败\n"); EVP_PKEY_free(pkey); return EXIT_FAILURE; } // 分配内存存储DER编码数据 der_pubkey = (uint8_t *)malloc(der_len); if (!der_pubkey) { fprintf(stderr, "内存分配失败\n"); EVP_PKEY_free(pkey); return EXIT_FAILURE; } // 第二步:序列化EVP_PKEY到DER格式内存 uint8_t *write_ptr = der_pubkey; i2d_PUBKEY(pkey, &write_ptr); // 此时der_pubkey即为DER编码的公钥,der_len为其字节长度 printf("DER编码公钥长度:%d字节\n", der_len); // 资源清理:释放所有分配的内存和OpenSSL结构体 free(der_pubkey); EVP_PKEY_free(pkey); return EXIT_SUCCESS; }
核心逻辑说明
- PEM解析:通过
BIO_new_mem_buf将内存中的PEM字符串包装为BIO输入流,再用PEM_read_bio_PUBKEY解析为OpenSSL通用密钥结构体EVP_PKEY,该结构体支持RSA、EC等多种密钥类型。 - i2d_PUBKEY使用要点:
- 首次调用传入
NULL作为第二个参数,函数返回DER数据的总长度,用于提前分配足够内存。 - 二次调用传入指向分配好内存的指针地址(
&write_ptr),函数会将DER数据写入内存,并自动移动指针到数据末尾。
- 首次调用传入
- 资源管理:所有OpenSSL创建的结构体(
EVP_PKEY、BIO)必须调用对应free函数释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Qi Huaping
相关产品推荐
相关产品推荐

