在openssl3.0+的版本上已经支持国密算法,在openssl3.0.x的版本中,使用的是EVP统一接口+provider。
Provider是算法的实现提供者,可以动态加载卸载。主要类型如下:
cpp
-default:默认提供者(包含主流算法)
-legacy:遗留算法提供者(不安全的旧算法)
-fips:FIPS认证算法提供者
-base:基础功能提供者
EVP(Envelope)统一接口,是算法操作的统一操作层。
cpp
应用程序->EVP统一接口->Provider实现
(做什么) (怎么做)
Provider加载方式
cpp
#include<openssl/openssl.h>
//1.显式加载Provider
OSSL_PROVIDER *legacy = OSSL_PROVIDER_load(NULL,"legacy");
OSSL_PROVIDER *default = OSSL_PROVIDER_load(NULL,"default")
//2.卸载Provider
OSSL_PROVIDER_load(legacy);
legacy = NULL;
Evp接口
cpp
//摘要算法(哈希)
EVP_MD_CTX //SM3,SHA256
//对称加密
EVP_CIPHER_CTX //SM4,AES...
//非对称加密/签名
EVP_PKEY_CTX //SM2,RSA...
//密钥派生
EVP_KDF_CTX //PBKDF2,HKDF...
//消息认证码
EVP_MAC_CTX //HMAC,CMAC...
EVP工作原理
cpp
EVP_MD_CTX *md_ctx = NULL;
EVP_MD *md = NULL;
ctx = EVP_MD_CTX_new();
md = EVP_sm3();
下面提供算法实现SM2,SM3,SM4:
cpp
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/provider.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void print_hex(const char* label, const unsigned char* data, size_t len) {
printf("%s: ", label);
for (size_t i = 0; i < len; i++) {
printf("%02x", data[i]);
}
printf("\n");
}
void handle_errors(void) {
ERR_print_errors_fp(stderr);
abort();
}
// 全局 providers
static OSSL_PROVIDER *legacy_provider = NULL;
static OSSL_PROVIDER *default_provider = NULL;
// 初始化 OpenSSL 3.x providers
int init_openssl_providers(void) {
static int initialized = 0;
if (!initialized) {
// OpenSSL 3.x 初始化
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
OPENSSL_INIT_ADD_ALL_CIPHERS |
OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
// 加载 legacy provider(包含国密算法)
legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
if (!legacy_provider) {
printf("警告:无法加载 legacy provider,国密算法可能不可用\n");
}
// 加载 default provider
default_provider = OSSL_PROVIDER_load(NULL, "default");
if (!default_provider) {
printf("错误:无法加载 default provider\n");
return 0;
}
initialized = 1;
printf("OpenSSL providers 初始化成功\n");
}
return 1;
}
// 清理 providers
void cleanup_openssl_providers(void) {
if (legacy_provider) {
OSSL_PROVIDER_unload(legacy_provider);
legacy_provider = NULL;
}
if (default_provider) {
OSSL_PROVIDER_unload(default_provider);
default_provider = NULL;
}
// OpenSSL 3.x 不需要 EVP_cleanup()
// 但可以调用通用的清理函数
EVP_cleanup();
ERR_free_strings();
}
// ==================== SM3实现 ====================
int sm3_demo() {
printf("\n=== SM3哈希算法示例 ===\n");
EVP_MD_CTX *md_ctx = NULL;
const EVP_MD *md = NULL;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_len = 0;
const char *message = "Hello SM3! 测试消息";
// 1. 创建消息摘要上下文
md_ctx = EVP_MD_CTX_new();
if (md_ctx == NULL) {
handle_errors();
}
// 2. 获取SM3摘要算法
md = EVP_sm3();
if (md == NULL) {
printf("SM3算法不可用,请检查OpenSSL配置\n");
// 尝试使用新的 API 获取
md = EVP_MD_fetch(NULL, "SM3", NULL);
if (!md) {
printf("错误:无法获取 SM3 算法\n");
EVP_MD_CTX_free(md_ctx);
return 0;
}
}
// 3. 初始化、更新、完成
if (1 != EVP_DigestInit_ex(md_ctx, md, NULL)) {
handle_errors();
}
if (1 != EVP_DigestUpdate(md_ctx, message, strlen(message))) {
handle_errors();
}
if (1 != EVP_DigestFinal_ex(md_ctx, digest, &digest_len)) {
handle_errors();
}
printf("原始数据: %s\n", message);
print_hex("SM3哈希值", digest, digest_len);
// 4. 清理
EVP_MD_CTX_free(md_ctx);
// 如果使用了 EVP_MD_fetch,需要释放
if (md != EVP_sm3()) {
EVP_MD_free((EVP_MD*)md);
}
return 1;
}
// ==================== SM4实现 ====================
int sm4_demo() {
printf("\n=== SM4对称加密示例 ===\n");
EVP_CIPHER_CTX *ctx = NULL;
const EVP_CIPHER *cipher = NULL;
// SM4-CBC参数
unsigned char key[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
unsigned char iv[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
unsigned char plaintext[] = "这是一个SM4加密测试消息";
unsigned char ciphertext[256];
unsigned char decryptedtext[256];
int ciphertext_len = 0, decryptedtext_len = 0;
int plaintext_len = strlen((char *)plaintext);
int len = 0;
printf("原始数据: %s\n", plaintext);
print_hex("SM4密钥", key, 16);
print_hex("初始化向量(IV)", iv, 16);
// ========== 加密 ==========
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) handle_errors();
cipher = EVP_sm4_cbc();
if (cipher == NULL) {
// 尝试使用新 API 获取
cipher = EVP_CIPHER_fetch(NULL, "SM4-CBC", NULL);
if (cipher == NULL) {
printf("SM4算法不可用\n");
EVP_CIPHER_CTX_free(ctx);
return 0;
}
}
// 初始化加密
if (1 != EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) {
handle_errors();
}
// 设置PKCS7填充(默认)
EVP_CIPHER_CTX_set_padding(ctx, 1);
// 执行加密
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
handle_errors();
}
ciphertext_len = len;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
handle_errors();
}
ciphertext_len += len;
print_hex("加密结果", ciphertext, ciphertext_len);
// ========== 解密 ==========
// 重置上下文
if (1 != EVP_CIPHER_CTX_reset(ctx)) {
handle_errors();
}
// 初始化解密
if (1 != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) {
handle_errors();
}
// 执行解密
if (1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len)) {
handle_errors();
}
decryptedtext_len = len;
if (1 != EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len)) {
handle_errors();
}
decryptedtext_len += len;
// 添加字符串结束符
decryptedtext[decryptedtext_len] = '\0';
printf("解密结果: %s\n", decryptedtext);
// 清理
EVP_CIPHER_CTX_free(ctx);
// 如果使用了 EVP_CIPHER_fetch,需要释放
if (cipher != EVP_sm4_cbc()) {
EVP_CIPHER_free((EVP_CIPHER*)cipher);
}
return 1;
}
// ==================== SM2实现 ====================
int sm2_demo() {
printf("\n=== SM2非对称加密示例 ===\n");
// 确保 providers 已加载
if (!init_openssl_providers()) {
printf("错误:OpenSSL providers 初始化失败\n");
return 0;
}
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
size_t outlen = 0;
unsigned char plaintext[] = "这是一个SM2加密测试消息";
unsigned char *ciphertext = NULL;
unsigned char *decrypted = NULL;
size_t plaintext_len = strlen((char *)plaintext);
size_t ciphertext_len = 0, decrypted_len = 0;
printf("原始数据: %s\n", plaintext);
// ========== 生成SM2密钥对 ==========
printf("1. 生成SM2密钥对...\n");
// OpenSSL 3.x 推荐使用新 API
pctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL);
if (!pctx) {
// 回退到旧 API
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
if (!pctx) {
handle_errors();
}
if (EVP_PKEY_keygen_init(pctx) <= 0) {
handle_errors();
}
// 设置SM2曲线参数
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, 1172) <= 0) {
printf("错误:SM2曲线不可用,NID_sm2=1172\n");
EVP_PKEY_CTX_free(pctx);
return 0;
}
} else {
// 新 API
if (EVP_PKEY_keygen_init(pctx) <= 0) {
handle_errors();
}
}
// 生成密钥对
if (EVP_PKEY_generate(pctx, &pkey) <= 0) {
handle_errors();
}
printf(" 密钥对生成成功\n");
printf(" 密钥位数: %d bits\n", EVP_PKEY_get_bits(pkey));
// ========== 加密 ==========
printf("2. 使用公钥加密...\n");
ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx) {
handle_errors();
}
if (EVP_PKEY_encrypt_init(ctx) <= 0) {
handle_errors();
}
// 获取输出长度
if (EVP_PKEY_encrypt(ctx, NULL, &outlen, plaintext, plaintext_len) <= 0) {
handle_errors();
}
ciphertext = (unsigned char *)malloc(outlen);
if (!ciphertext) {
printf("内存分配失败\n");
goto cleanup;
}
// 执行加密
if (EVP_PKEY_encrypt(ctx, ciphertext, &outlen, plaintext, plaintext_len) <= 0) {
printf("加密失败,错误信息:\n");
ERR_print_errors_fp(stderr);
// 可能是算法不支持,尝试使用 SM2-specific 上下文
EVP_PKEY_CTX_free(ctx);
ctx = EVP_PKEY_CTX_new(pkey, NULL);
// 设置 SM2 特定的加密参数
if (EVP_PKEY_encrypt_init(ctx) <= 0 ||
EVP_PKEY_encrypt(ctx, ciphertext, &outlen, plaintext, plaintext_len) <= 0) {
printf("SM2加密完全失败\n");
goto cleanup;
}
}
ciphertext_len = outlen;
printf(" 加密成功,密文长度: %zu bytes\n", ciphertext_len);
print_hex(" 密文(前64字节)", ciphertext, ciphertext_len > 64 ? 64 : ciphertext_len);
// ========== 解密 ==========
printf("3. 使用私钥解密...\n");
// 创建新的解密上下文
EVP_PKEY_CTX_free(ctx);
ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx) {
handle_errors();
}
if (EVP_PKEY_decrypt_init(ctx) <= 0) {
handle_errors();
}
// 获取输出长度
if (EVP_PKEY_decrypt(ctx, NULL, &outlen, ciphertext, ciphertext_len) <= 0) {
handle_errors();
}
decrypted = (unsigned char *)malloc(outlen + 1); // +1 for null terminator
if (!decrypted) {
printf("内存分配失败\n");
goto cleanup;
}
// 执行解密
if (EVP_PKEY_decrypt(ctx, decrypted, &outlen, ciphertext, ciphertext_len) <= 0) {
printf("解密失败,错误信息:\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
decrypted_len = outlen;
decrypted[decrypted_len] = '\0';
printf(" 解密成功,解密长度: %zu bytes\n", decrypted_len);
printf(" 解密结果: %s\n", decrypted);
// ========== 清理 ==========
cleanup:
if (ciphertext) free(ciphertext);
if (decrypted) free(decrypted);
if (ctx) EVP_PKEY_CTX_free(ctx);
if (pctx) EVP_PKEY_CTX_free(pctx);
if (pkey) EVP_PKEY_free(pkey);
return 1;
}
// ==================== 综合示例:数值加密 ====================
int number_encryption_demo() {
printf("\n=== 数值加密综合示例 ===\n");
// 确保 providers 已加载
if (!init_openssl_providers()) {
printf("错误:OpenSSL providers 初始化失败\n");
return 0;
}
// 准备要加密的数值
int original_number = 1234567890;
unsigned char number_bytes[sizeof(int)];
memcpy(number_bytes, &original_number, sizeof(int));
printf("原始数值: %d\n", original_number);
print_hex("数值字节表示", number_bytes, sizeof(int));
// 1. 使用SM3计算数值的哈希
printf("\n1. SM3哈希验证:\n");
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
const EVP_MD *md = EVP_sm3();
if (!md) {
md = EVP_MD_fetch(NULL, "SM3", NULL);
}
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int hash_len = 0;
if (md && md_ctx) {
EVP_DigestInit_ex(md_ctx, md, NULL);
EVP_DigestUpdate(md_ctx, number_bytes, sizeof(int));
EVP_DigestFinal_ex(md_ctx, hash, &hash_len);
print_hex(" SM3哈希值", hash, hash_len);
}
// 2. 使用SM4加密数值
printf("\n2. SM4加密数值:\n");
unsigned char sm4_key[16] = {0};
unsigned char sm4_iv[16] = {0};
// 生成随机密钥和IV
if (RAND_bytes(sm4_key, sizeof(sm4_key)) <= 0 ||
RAND_bytes(sm4_iv, sizeof(sm4_iv)) <= 0) {
printf("错误:无法生成随机数\n");
} else {
print_hex(" 随机SM4密钥", sm4_key, sizeof(sm4_key));
print_hex(" 随机IV", sm4_iv, sizeof(sm4_iv));
}
EVP_CIPHER_CTX *cipher_ctx = EVP_CIPHER_CTX_new();
const EVP_CIPHER *cipher = EVP_sm4_cbc();
if (!cipher) {
cipher = EVP_CIPHER_fetch(NULL, "SM4-CBC", NULL);
}
unsigned char encrypted_number[256];
int enc_len = 0, total_enc_len = 0;
if (cipher && cipher_ctx) {
// 加密
EVP_EncryptInit_ex(cipher_ctx, cipher, NULL, sm4_key, sm4_iv);
EVP_EncryptUpdate(cipher_ctx, encrypted_number, &enc_len,
number_bytes, sizeof(int));
total_enc_len = enc_len;
EVP_EncryptFinal_ex(cipher_ctx, encrypted_number + enc_len, &enc_len);
total_enc_len += enc_len;
print_hex(" SM4加密结果", encrypted_number, total_enc_len);
// 解密
unsigned char decrypted_bytes[256];
int dec_len = 0, total_dec_len = 0;
EVP_CIPHER_CTX_reset(cipher_ctx);
EVP_DecryptInit_ex(cipher_ctx, cipher, NULL, sm4_key, sm4_iv);
EVP_DecryptUpdate(cipher_ctx, decrypted_bytes, &dec_len,
encrypted_number, total_enc_len);
total_dec_len = dec_len;
EVP_DecryptFinal_ex(cipher_ctx, decrypted_bytes + dec_len, &dec_len);
total_dec_len += dec_len;
// 转换回整数
int decrypted_number;
memcpy(&decrypted_number, decrypted_bytes, sizeof(int));
printf(" 解密后数值: %d\n", decrypted_number);
if (original_number == decrypted_number) {
printf(" ✓ SM4加解密验证成功\n");
} else {
printf(" ✗ SM4加解密验证失败\n");
}
}
// 3. 清理
if (md_ctx) EVP_MD_CTX_free(md_ctx);
if (cipher_ctx) EVP_CIPHER_CTX_free(cipher_ctx);
// 释放 fetch 的资源
if (md && md != EVP_sm3()) {
EVP_MD_free((EVP_MD*)md);
}
if (cipher && cipher != EVP_sm4_cbc()) {
EVP_CIPHER_free((EVP_CIPHER*)cipher);
}
return 1;
}
int main() {
printf("========================================\n");
printf("OpenSSL EVP国密算法演示 (OpenSSL 3.x兼容版)\n");
printf("OpenSSL版本: %s\n", OpenSSL_version(OPENSSL_VERSION));
printf("========================================\n");
// 初始化 OpenSSL 3.x providers
if (!init_openssl_providers()) {
printf("错误:无法初始化 OpenSSL\n");
return 1;
}
// 测试各算法
int sm3_ok = sm3_demo(); // SM3哈希
int sm4_ok = sm4_demo(); // SM4对称加密
int sm2_ok = sm2_demo(); // SM2非对称加密
int number_ok = number_encryption_demo(); // 数值加密示例
// 清理
cleanup_openssl_providers();
printf("\n========================================\n");
printf("演示完成\n");
printf("算法支持状态:\n");
printf(" SM3哈希: %s\n", sm3_ok ? "✓ 支持" : "✗ 不支持");
printf(" SM4加密: %s\n", sm4_ok ? "✓ 支持" : "✗ 不支持");
printf(" SM2加密: %s\n", sm2_ok ? "✓ 支持" : "✗ 不支持");
printf(" 数值加密: %s\n", number_ok ? "✓ 支持" : "✗ 不支持");
printf("========================================\n");
return 0;
}