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

如何使用OpenSSL EVP函数实现RSA公钥加密?

用OpenSSL EVP高级函数实现RSA公钥加密的正确姿势

你找不到对应RSA的EVP_CIPHER类型是完全正常的——因为RSA作为非对称加密算法,在OpenSSL的EVP框架里不属于对称加密的EVP_CIPHER体系,而是归属于非对称加密的EVP_PKEY体系。这是两类加密算法在设计逻辑和使用场景上的本质区别导致的:

  • AES这类对称加密算法,核心是通过固定的加密模式(比如CBC、GCM)对数据流进行分段处理,所以用EVP_CIPHER来描述算法和模式,配合EVP_EncryptInit_ex()/EVP_EncryptUpdate()/EVP_EncryptFinal_ex()来处理流式数据;
  • RSA这类非对称加密算法,通常用于加密小数据(比如对称密钥),它的加密逻辑是基于密钥对的数学运算,所以使用EVP_PKEY(代表非对称密钥)和对应的上下文EVP_PKEY_CTX来操作,不需要EVP_CIPHER。

具体实现步骤&代码示例

下面是一个完整的用EVP高级函数实现RSA公钥加密的示例,包含公钥加载、加密操作和资源清理:

1. 核心逻辑说明

RSA公钥加密在EVP框架中主要使用EVP_PKEY_encrypt()函数(因为RSA加密通常不需要流式处理小数据),如果要处理大文件,正确的做法是混合加密:用AES加密文件,再用RSA加密AES密钥——这也是实际场景的标准用法。

2. 代码示例

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

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

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

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

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

    // 3. 设置加密参数(比如使用OAEP padding,比PKCS#1 v1.5更安全)
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
        handle_errors();
    }

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

    // 5. 执行加密操作
    if (EVP_PKEY_encrypt(ctx, ciphertext, &ciphertext_len, plaintext, plaintext_len) <= 0) {
        handle_errors();
    }

    // 6. 清理资源
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pub_key);

    return ciphertext_len;
}

int main(void) {
    // 初始化OpenSSL错误处理和算法库
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    const unsigned char *plaintext = "Hello, RSA Encryption with EVP!";
    int plaintext_len = strlen((char *)plaintext);
    unsigned char ciphertext[256]; // 2048位RSA加密后最多256字节

    // 替换为你的公钥文件路径
    int cipher_len = rsa_public_encrypt(plaintext, plaintext_len, "public_key.pem", ciphertext);
    if (cipher_len > 0) {
        printf("Encryption successful! Ciphertext length: %d bytes\n", cipher_len);
    }

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

    return 0;
}

关键注意事项

  • 明文长度限制:RSA加密的明文长度不能超过密钥长度/8 - padding长度,比如2048位RSA用OAEP padding时,最多能加密245字节左右。如果要加密大文件,一定要用混合加密方案;
  • Padding选择:优先使用RSA_PKCS1_OAEP_PADDING,它比默认的RSA_PKCS1_PADDING更安全,能抵抗更多攻击;
  • 资源清理:所有OpenSSL创建的结构(EVP_PKEY、EVP_PKEY_CTX等)都要记得调用对应的_free函数释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者void.pointer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:46:05