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

使用OpenSSL生成RSA密钥对后读取失败,求正确实现方法

解决OpenSSL生成RSA密钥对后读取失败的问题

你遇到的error:0906D06C:PEM routines:PEM_read_bio:no start line错误,核心原因是密钥生成的格式和读取时使用的函数不匹配,再加上代码里有一处判断错误,导致读取失败。我来帮你拆解问题并修复代码:

问题分析

  1. 公钥格式不匹配:

    • 你用PEM_write_bio_RSAPublicKey生成的是PKCS#1格式的公钥,开头是-----BEGIN RSA PUBLIC KEY-----
    • 但读取时用的PEM_read_bio_PUBKEY是用来读取PKCS#8格式的公钥,开头是-----BEGIN PUBLIC KEY-----
      两种格式的PEM头部不同,所以读取时找不到起始行,触发错误。
  2. 私钥读取判断错误:
    代码里判断私钥读取失败的条件写错了:用了evp_pbkey == NULL(公钥的指针),而不是evp_pkey == NULL,导致无法正确检测私钥读取的问题。

  3. (可选)内存BIO指针位置:
    写入密钥到内存BIO后,指针会停在末尾,虽然你用BIO_pending获取了长度,但有时候建议重置BIO指针到开头再读取,避免意外的读取问题。

修复方案(两种可选)

方案一:统一使用PKCS#1格式(保持生成函数,修改读取函数)

这种方案不需要改生成逻辑,只需要把读取公钥和私钥的函数换成对应PKCS#1格式的:

  • 公钥读取用PEM_read_bio_RSAPublicKey
  • 私钥读取用PEM_read_bio_RSAPrivateKey

方案二:统一使用PKCS#8格式(修改生成函数,保持读取函数)

如果你更倾向于标准的PKCS#8格式,把生成函数换成:

  • 公钥生成用PEM_write_bio_PUBKEY
  • 私钥生成用PEM_write_bio_PrivateKey

下面是用方案一修复后的完整代码,同时修正了判断错误和内存BIO的指针问题:

#include <stdio.h>
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <exception>
#include <stdlib.h>

bool generate_key() {
    size_t pri_len; // Length of private key
    size_t pub_len; // Length of public key
    char *pri_key = nullptr; // Private key in PEM
    char *pub_key = nullptr; // Public key in PEM
    int ret = 0;
    RSA *r = NULL;
    BIGNUM *bne = NULL;
    BIO *bp_public = NULL, *bp_private = NULL;
    int bits = 2048;
    unsigned long e = RSA_F4;
    RSA *read_pub_rsa = NULL; // 用RSA结构体读取PKCS#1公钥
    RSA *read_priv_rsa = NULL; // 用RSA结构体读取PKCS#1私钥
    BIO *pbkeybio = NULL;
    BIO *pkeybio = NULL;

    // 1. generate rsa key
    bne = BN_new();
    ret = BN_set_word(bne, e);
    if (ret != 1) {
        goto free_all;
    }
    r = RSA_new();
    ret = RSA_generate_key_ex(r, bits, bne, NULL);
    if (ret != 1) {
        goto free_all;
    }

    // 2. save public key (PKCS#1格式)
    bp_public = BIO_new(BIO_s_mem());
    ret = PEM_write_bio_RSAPublicKey(bp_public, r);
    if (ret != 1) {
        goto free_all;
    }

    // 3. save private key (PKCS#1格式)
    bp_private = BIO_new(BIO_s_mem());
    ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
    if (ret != 1) {
        goto free_all;
    }

    //4. Get the keys as PEM formatted strings
    // 重置BIO指针到开头,确保能读取到完整内容
    BIO_reset(bp_public);
    BIO_reset(bp_private);

    pri_len = BIO_pending(bp_private);
    pub_len = BIO_pending(bp_public);
    pri_key = (char*) malloc(pri_len + 1);
    pub_key = (char*) malloc(pub_len + 1);
    if (!pri_key || !pub_key) {
        ret = 0;
        goto free_all;
    }
    BIO_read(bp_private, pri_key, pri_len);
    BIO_read(bp_public, pub_key, pub_len);
    pri_key[pri_len] = '\0';
    pub_key[pub_len] = '\0';

    printf("\nPrivate Key:\n%s\nPublic Key:\n%s\n", pri_key, pub_key);

    // 验证公钥读取(PKCS#1格式对应PEM_read_bio_RSAPublicKey)
    pbkeybio = BIO_new_mem_buf((void*) pub_key, -1);
    if (pbkeybio == NULL) {
        ret = 0;
        goto free_all;
    }
    read_pub_rsa = PEM_read_bio_RSAPublicKey(pbkeybio, &read_pub_rsa, NULL, NULL);
    if (read_pub_rsa == NULL) {
        char buffer[120];
        ERR_error_string(ERR_get_error(), buffer);
        printf("Error reading public key:%s\n", buffer);
        ret = 0;
    } else {
        printf("Public key read successfully!\n");
    }

    // 验证私钥读取(PKCS#1格式对应PEM_read_bio_RSAPrivateKey)
    pkeybio = BIO_new_mem_buf((void*) pri_key, -1);
    if (pkeybio == NULL) {
        ret = 0;
        goto free_all;
    }
    read_priv_rsa = PEM_read_bio_RSAPrivateKey(pkeybio, &read_priv_rsa, NULL, NULL);
    if (read_priv_rsa == NULL) { // 修正:这里用read_priv_rsa判断,不是evp_pbkey
        char buffer[120];
        ERR_error_string(ERR_get_error(), buffer);
        printf("Error reading private key:%s\n", buffer);
        ret = 0;
    } else {
        printf("Private key read successfully!\n");
    }

    // 4. free resources
free_all:
    BIO_free(pbkeybio);
    BIO_free(pkeybio);
    BIO_free_all(bp_public);
    BIO_free_all(bp_private);
    RSA_free(r);
    RSA_free(read_pub_rsa);
    RSA_free(read_priv_rsa);
    BN_free(bne);
    free(pri_key);
    free(pub_key);
    return (ret == 1);
}

int main(int argc, char* argv[]) {
    // 初始化OpenSSL错误处理
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    bool success = generate_key();
    if (success) {
        printf("\nKey generation and verification completed successfully!\n");
    } else {
        printf("\nOperation failed!\n");
    }

    // 清理OpenSSL资源
    EVP_cleanup();
    ERR_free_strings();

    return 0;
}

额外注意事项

  • 别忘了初始化OpenSSL的错误处理和算法库(代码里加了ERR_load_crypto_strings()和OpenSSL_add_all_algorithms()),否则错误信息可能无法正常输出。
  • 内存分配后要检查是否成功,避免空指针访问。
  • 所有OpenSSL的结构体和BIO都要记得释放,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:03:25