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

OpenSSL 3.0 C++中使用RSA公钥加密的现代方法(替代弃用的RSA_public_encrypt)

OpenSSL 3.0+ 替代 RSA_public_encrypt 的现代 RSA 公钥加密方式

OpenSSL 3.0 弃用 RSA_public_encrypt 这类低阶RSA API,核心原因是这类接口要求开发者手动处理填充、密钥管理等细节,极易引入安全漏洞。现代推荐使用EVP高层加密API——它封装了密码学操作的通用逻辑,支持更安全的填充方式(如RSA-OAEP),且兼容性、可维护性更强。

核心实现步骤(C语言示例)

以下是使用EVP API实现RSA公钥加密的完整流程,以PEM格式公钥为例:

  1. 加载RSA公钥
    从PEM文件或内存中读取公钥,解析为EVP_PKEY对象(OpenSSL 3.0中统一用该结构管理各类密钥)。

  2. 初始化加密上下文
    创建EVP_PKEY_CTX上下文,绑定公钥并指定加密算法(优先选RSA-OAEP,比传统PKCS#1 v1.5更安全)。

  3. 执行加密操作
    调用EVP_PKEY_encrypt系列函数完成加密,自动处理填充逻辑。

  4. 清理资源
    释放所有OpenSSL对象,避免内存泄漏。

完整代码示例

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

// 错误处理辅助函数
static void handle_errors(void) {
    ERR_print_errors_fp(stderr);
    abort();
}

// RSA公钥加密函数(使用RSA-OAEP填充)
int rsa_public_encrypt(const unsigned char *plaintext, size_t plaintext_len,
                       const char *pub_key_path, unsigned char **ciphertext) {
    EVP_PKEY *pub_key = NULL;
    EVP_PKEY_CTX *ctx = NULL;
    size_t ciphertext_len = 0;

    // 1. 加载PEM格式公钥
    FILE *pub_file = fopen(pub_key_path, "r");
    if (!pub_file) {
        perror("Failed to open public key file");
        return -1;
    }
    pub_key = PEM_read_PUBKEY(pub_file, NULL, NULL, NULL);
    fclose(pub_file);
    if (!pub_key) {
        fprintf(stderr, "Failed to read public key\n");
        handle_errors();
    }

    // 2. 创建并初始化加密上下文
    ctx = EVP_PKEY_CTX_new(pub_key, NULL);
    if (!ctx) handle_errors();
    if (EVP_PKEY_encrypt_init(ctx) <= 0) handle_errors();

    // 指定使用RSA-OAEP填充(默认SHA-256,可手动指定哈希算法)
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) handle_errors();
    // 可选:指定OAEP使用的哈希算法,比如SHA-512
    // if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha512()) <= 0) handle_errors();

    // 3. 获取加密后数据长度
    if (EVP_PKEY_encrypt(ctx, NULL, &ciphertext_len, plaintext, plaintext_len) <= 0) handle_errors();

    // 分配内存存储密文
    *ciphertext = malloc(ciphertext_len);
    if (!*ciphertext) {
        fprintf(stderr, "Memory allocation failed\n");
        goto cleanup;
    }

    // 执行加密
    if (EVP_PKEY_encrypt(ctx, *ciphertext, &ciphertext_len, plaintext, plaintext_len) <= 0) handle_errors();

cleanup:
    // 清理资源
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pub_key);

    return ciphertext_len;
}

// 测试用例
int main(void) {
    const unsigned char *plaintext = "Hello, RSA-OAEP Encryption!";
    const char *pub_key_path = "public_key.pem";
    unsigned char *ciphertext = NULL;
    int ciphertext_len;

    // 初始化OpenSSL错误处理
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    ciphertext_len = rsa_public_encrypt(plaintext, strlen((char*)plaintext), pub_key_path, &ciphertext);
    if (ciphertext_len <= 0) {
        fprintf(stderr, "Encryption failed\n");
        return 1;
    }

    printf("Encrypted data length: %d bytes\n", ciphertext_len);
    // 可将密文写入文件或传输,此处省略

    free(ciphertext);
    ERR_free_strings();
    return 0;
}

关键注意事项

  • 填充方式选择:优先使用RSA_PKCS1_OAEP_PADDING(RSA-OAEP),它比旧的RSA_PKCS1_PADDING(PKCS#1 v1.5)更安全,能抵御选择密文攻击(CCA)。
  • 数据长度限制:RSA加密仅适合小数据(比如对称密钥),2048位RSA密钥使用OAEP填充时,最大可加密2048/8 - 2*哈希长度 - 2字节(SHA-256对应245字节)。如果要加密大文件,正确流程是:
    1. 生成随机对称密钥(比如AES-256)
    2. 用AES加密大文件
    3. 用RSA公钥加密AES密钥
  • 错误处理:必须检查每个OpenSSL函数的返回值,避免忽略潜在的安全问题。
  • OpenSSL 3.0兼容性:如果使用OpenSSL 3.0的provider机制,可通过EVP_PKEY_CTX_set_provider指定加密提供者(默认是default provider,已包含RSA算法)。

内容的提问来源于stack exchange,提问作者Mikołaj Gogola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:20:46