You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSSL 3.0加载PEM格式RSA密钥问题求助

OpenSSL 3.0 从PEM加载RSA密钥并获取参数的正确方式

核心问题分析

你之前的代码崩溃主要有两个原因:

  1. 公钥文件里根本没有私钥参数d,强行调用EVP_PKEY_get_bn_param获取不存在的参数会导致非法访问
  2. 直接用EVP_PKEY_get_bn_param获取RSA参数不是OpenSSL 3.0推荐的方式,且缺乏必要的错误检查

正确实现步骤

1. 加载RSA密钥(公钥/私钥)

OpenSSL 3.0依然支持对应旧版本的加载函数,只是返回类型从RSA*改为EVP_PKEY*:

  • 加载PKCS#8格式公钥(对应旧函数PEM_read_bio_RSA_PUBKEY):
EVP_PKEY* pub_key = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
  • 加载传统SSLeay格式RSA公钥(对应旧函数PEM_read_bio_RSAPublicKey):
EVP_PKEY* pub_key = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
  • 加载RSA私钥:
// 通用私钥加载(支持PKCS#8格式)
EVP_PKEY* priv_key = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
// 或者传统RSA私钥格式
EVP_PKEY* priv_key = PEM_read_bio_RSAPrivateKey(bp, NULL, NULL, NULL);

2. 安全获取RSA参数

先将EVP_PKEY转换为RSA*结构,再用OpenSSL 3.0推荐的RSA_get0_*系列函数获取参数(这些函数返回的是只读指针,无需手动释放):

#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/err.h>

// 示例:加载公钥并获取n、e
BIO* bp = BIO_new_file("public.pem", "r");
if (!bp) {
    perror("Failed to open PEM file");
    return -1;
}

EVP_PKEY* pub_key = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
BIO_free(bp);

if (!pub_key) {
    ERR_print_errors_fp(stderr);
    return -1;
}

// 验证是否为RSA密钥
if (EVP_PKEY_id(pub_key) != EVP_PKEY_RSA) {
    fprintf(stderr, "Not an RSA key\n");
    EVP_PKEY_free(pub_key);
    return -1;
}

// 获取RSA结构指针
const RSA* rsa = EVP_PKEY_get0_RSA(pub_key);
if (!rsa) {
    ERR_print_errors_fp(stderr);
    EVP_PKEY_free(pub_key);
    return -1;
}

// 获取公钥参数
const BIGNUM* n = RSA_get0_n(rsa);
const BIGNUM* e = RSA_get0_e(rsa);
// 这里可以使用n和e,比如打印:
BN_print_fp(stdout, n);
printf("\n");
BN_print_fp(stdout, e);
printf("\n");

// 示例:加载私钥并获取d、p、q等
bp = BIO_new_file("private.pem", "r");
EVP_PKEY* priv_key = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL);
BIO_free(bp);

if (priv_key && EVP_PKEY_id(priv_key) == EVP_PKEY_RSA) {
    const RSA* rsa_priv = EVP_PKEY_get0_RSA(priv_key);
    const BIGNUM* d = RSA_get0_d(rsa_priv);
    const BIGNUM* p = RSA_get0_p(rsa_priv);
    const BIGNUM* q = RSA_get0_q(rsa_priv);
    // 使用私钥参数
}

// 释放资源
EVP_PKEY_free(pub_key);
EVP_PKEY_free(priv_key);

关键注意事项

  • 必须检查所有OpenSSL函数的返回值,避免空指针访问
  • 公钥仅包含n和e,私钥才有d、p、q等参数,不要混淆
  • RSA_get0_*系列函数返回的是只读指针,不要尝试修改或释放它们,资源由EVP_PKEY管理,只需释放EVP_PKEY即可

内容的提问来源于stack exchange,提问作者Syxed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:15:20