OpenSSL 3.0加载PEM格式RSA密钥问题求助
OpenSSL 3.0 从PEM加载RSA密钥并获取参数的正确方式
核心问题分析
你之前的代码崩溃主要有两个原因:
- 公钥文件里根本没有私钥参数
d,强行调用EVP_PKEY_get_bn_param获取不存在的参数会导致非法访问 - 直接用
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
相关产品推荐
相关产品推荐

