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

C++中使用X509证书(.crt)的RSA公钥加密遇PEM读取错误求助

解决从X509证书提取RSA公钥并加密消息的问题

首先得说清你踩的坑:你遇到的 error:0906D06C:PEM routines:PEM_read_bio:no start line,核心原因是用错了函数——PEM_read_bio_RSA_PUBKEY 是用来读取独立的PEM格式公钥文件的,但你手里的是X509证书文件,它的开头是 -----BEGIN CERTIFICATE-----,和独立公钥的格式完全不一样,自然读不出来。正确的做法是先从证书里提取公钥对象,再转成RSA结构体,之后再做加密。

下面是具体的实现步骤(用C语言+OpenSSL举例):

1. 加载X509证书文件

先把.crt文件加载成OpenSSL的X509结构体:

#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 加载证书文件到X509结构体
X509* load_x509_cert(const char* cert_path) {
    FILE* cert_file = fopen(cert_path, "r");
    if (!cert_file) {
        perror("Failed to open certificate file");
        return NULL;
    }
    // 读取PEM格式的X509证书
    X509* cert = PEM_read_X509(cert_file, NULL, NULL, NULL);
    fclose(cert_file);
    if (!cert) {
        fprintf(stderr, "Failed to parse certificate: ");
        ERR_print_errors_fp(stderr);
        return NULL;
    }
    return cert;
}

2. 从证书中提取RSA公钥

证书里的公钥是EVP_PKEY通用类型,需要先取出,再转换成RSA专用结构体:

// 从X509证书中提取RSA公钥
RSA* extract_rsa_pubkey(X509* cert) {
    // 从证书中取出公钥
    EVP_PKEY* pkey = X509_get_pubkey(cert);
    if (!pkey) {
        fprintf(stderr, "Failed to get public key from cert: ");
        ERR_print_errors_fp(stderr);
        return NULL;
    }
    // 验证公钥是否为RSA类型
    if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
        fprintf(stderr, "Certificate's public key is not RSA type!\n");
        EVP_PKEY_free(pkey);
        return NULL;
    }
    // 转换成RSA结构体
    RSA* rsa_pub = EVP_PKEY_get1_RSA(pkey);
    EVP_PKEY_free(pkey); // 释放通用公钥对象,RSA结构体单独管理
    if (!rsa_pub) {
        fprintf(stderr, "Failed to convert EVP_PKEY to RSA: ");
        ERR_print_errors_fp(stderr);
    }
    return rsa_pub;
}

3. 用RSA公钥加密消息

接下来就可以用标准的RSA加密函数处理消息了,注意RSA加密的明文长度有限制(一般是密钥长度-11字节,因为用PKCS#1 v1.5填充):

// RSA公钥加密(PKCS#1 v1.5填充)
int rsa_public_encrypt_data(RSA* rsa_pub, const unsigned char* plaintext, int plaintext_len, unsigned char* ciphertext) {
    int rsa_key_size = RSA_size(rsa_pub);
    // 检查明文长度是否超过RSA加密上限
    if (plaintext_len > rsa_key_size - 11) {
        fprintf(stderr, "Plaintext is too long for RSA encryption! Max length: %d\n", rsa_key_size - 11);
        return -1;
    }
    // 执行加密
    int cipher_len = RSA_public_encrypt(plaintext_len, plaintext, ciphertext, rsa_pub, RSA_PKCS1_PADDING);
    if (cipher_len == -1) {
        fprintf(stderr, "RSA encryption failed: ");
        ERR_print_errors_fp(stderr);
    }
    return cipher_len;
}

4. 资源清理(重要)

用完OpenSSL的结构体后一定要释放,避免内存泄漏:

// 清理所有资源
void cleanup_resources(X509* cert, RSA* rsa_pub) {
    if (cert) X509_free(cert);
    if (rsa_pub) RSA_free(rsa_pub);
    ERR_free_strings();
}

完整调用示例

int main() {
    const char* cert_path = "your_certificate.crt";
    const char* plaintext = "This is the message to encrypt with RSA public key";
    int plaintext_len = strlen(plaintext);

    // 初始化OpenSSL(旧版本需要这两步,新版本可省略)
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    // 加载证书
    X509* cert = load_x509_cert(cert_path);
    if (!cert) return 1;

    // 提取RSA公钥
    RSA* rsa_pub = extract_rsa_pubkey(cert);
    if (!rsa_pub) {
        cleanup_resources(cert, NULL);
        return 1;
    }

    // 分配密文缓冲区
    int rsa_key_size = RSA_size(rsa_pub);
    unsigned char* ciphertext = malloc(rsa_key_size);
    if (!ciphertext) {
        perror("Failed to allocate ciphertext buffer");
        cleanup_resources(cert, rsa_pub);
        return 1;
    }

    // 执行加密
    int cipher_len = rsa_public_encrypt_data(rsa_pub, (unsigned char*)plaintext, plaintext_len, ciphertext);
    if (cipher_len == -1) {
        free(ciphertext);
        cleanup_resources(cert, rsa_pub);
        return 1;
    }

    // 这里可以处理密文,比如打印长度或保存到文件
    printf("Encryption success! Ciphertext length: %d bytes\n", cipher_len);

    // 清理资源
    free(ciphertext);
    cleanup_resources(cert, rsa_pub);
    return 0;
}

关键注意事项

  • 绝对不要用PEM_read_bio_RSA_PUBKEY直接读证书文件,这个函数只认-----BEGIN PUBLIC KEY-----开头的独立公钥文件。
  • 每个OpenSSL函数的返回值都要检查,出错时用ERR_print_errors_fp(stderr)打印详细错误信息,能帮你快速定位问题。
  • RSA不适合加密大文件,建议先用AES等对称加密算法加密文件,再用RSA加密对称密钥,这是业界通用的混合加密方案。

内容的提问来源于stack exchange,提问作者Дима Менько

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:46:00