如何用OpenSSL EVP函数替换3.0版本废弃的RSA低级API?
替换OpenSSL 3.0中废弃的RSA低级API为EVP高级API
原代码与问题
下面是一段原本可正常运行的OpenSSL RSA加密代码:
void SwapBytes( unsigned char *pv, size_t n ) { unsigned char *p = pv; size_t lo, hi; for ( lo = 0, hi = n - 1; hi > lo; lo++, hi-- ) { char tmp = p[lo]; p[lo] = p[hi]; p[hi] = tmp; } } void RSA(unsigned char *plaintext, unsigned char *ciphertext) { BIGNUM *bnN = NULL; BIGNUM *bnE = NULL; RSA *keys = RSA_new(); BN_hex2bn(&bnN, modulus); BN_hex2bn(&bnE, public_exp); RSA_set0_key(keys, bnN, bnE, NULL); int modulus_size = RSA_size(keys); SwapBytes(plaintext, modulus_size); int cipher_len = RSA_public_encrypt(modulus_size, plaintext, ciphertext, keys, RSA_NO_PADDING); RSA_free(keys); SwapBytes(ciphertext, modulus_size); }
编译时会触发废弃警告:
/mnt/c/Projects/src/rsa.cpp:37:102: warning: ‘int RSA_public_encrypt(int, const unsigned char*, unsigned char*, RSA*, int)’ is deprecated: Since OpenSSL 3.0 [-Wdeprecated-declarations] 37 | int cipher_len = RSA_public_encrypt(modulus_size, plaintext, ciphertext, keys, RSA_NO_PADDING);
虽然可以通过编译选项-Wno-deprecated-declarations抑制警告,但OpenSSL官方明确表示:
OpenSSL开发团队长期以来一直不建议使用低级API,在OpenSSL 3.0中这一要求被正式明确,所有此类低级API均已被废弃。你仍可在应用中使用它们,但编译时可能会出现废弃警告(取决于编译器是否支持该特性)。废弃的API可能会在未来版本的OpenSSL中被移除,因此强烈建议你将代码更新为使用高级API。
使用EVP高级API的替代实现
下面是使用OpenSSL EVP API重写的RSA加密代码,功能与原代码完全一致(无填充的RSA公钥加密,包含字节序反转):
#include <openssl/evp.h> #include <openssl/bn.h> #include <openssl/rsa.h> void SwapBytes(unsigned char *pv, size_t n) { unsigned char *p = pv; size_t lo, hi; for (lo = 0, hi = n - 1; hi > lo; lo++, hi--) { char tmp = p[lo]; p[lo] = p[hi]; p[hi] = tmp; } } int RSA_EVP_Encrypt(unsigned char *plaintext, unsigned char *ciphertext, size_t *cipher_len) { // 假设modulus和public_exp是全局定义的十六进制字符串常量 BIGNUM *bnN = BN_hex2bn(NULL, modulus); BIGNUM *bnE = BN_hex2bn(NULL, public_exp); if (bnN == NULL || bnE == NULL) return -1; RSA *rsa_key = RSA_new(); if (RSA_set0_key(rsa_key, bnN, bnE, NULL) != 1) { RSA_free(rsa_key); BN_free(bnN); BN_free(bnE); return -1; } EVP_PKEY *pkey = EVP_PKEY_new(); if (EVP_PKEY_assign_RSA(pkey, rsa_key) != 1) { EVP_PKEY_free(pkey); RSA_free(rsa_key); return -1; } EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); if (ctx == NULL) { EVP_PKEY_free(pkey); return -1; } if (EVP_PKEY_encrypt_init(ctx) != 1) { EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return -1; } // 设置无填充模式,对应原代码的RSA_NO_PADDING if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) { EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return -1; } int modulus_size = RSA_size(rsa_key); SwapBytes(plaintext, modulus_size); // 执行加密操作 if (EVP_PKEY_encrypt(ctx, ciphertext, cipher_len, plaintext, modulus_size) != 1) { EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return -1; } SwapBytes(ciphertext, modulus_size); // 清理资源:EVP_PKEY_free会自动释放关联的RSA结构和BIGNUM EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return 0; }
代码说明
- 使用
EVP_PKEY作为密钥的统一抽象层,兼容多种加密算法,符合OpenSSL 3.0的设计规范 - 通过
EVP_PKEY_assign_RSA将原有RSA密钥结构关联到EVP_PKEY,实现低级密钥结构到高级API的过渡 - 用
EVP_PKEY_CTX配置加密参数,这里设置无填充模式,与原代码逻辑对齐 - 加密流程通过
EVP_PKEY_encrypt_init初始化、EVP_PKEY_encrypt执行完成,结构更清晰 - 资源清理更简洁:
EVP_PKEY_free会自动释放关联的RSA和BIGNUM结构,无需手动逐个释放
内容的提问来源于stack exchange,提问作者vengy
相关产品推荐
相关产品推荐

