SM4-CBC算法调用示例
保存以下代码至sm4_cbc_demo.c,编译运行。
gcc -o sm4_cbc_demo sm4_cbc_demo.c -lssl -lcrypto -ldl ./sm4_cbc_demo
/**
* sm4_cbc_demo.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#define ENGINE_SO_PATH "/usr/lib64/libsdf_engine.so"
#define SDF_LIB_PATH "/usr/lib64/libsdf.so"
static ENGINE *g_engine = NULL;
static const unsigned char g_key16[] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
};
static const unsigned char g_iv16[] = {
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
};
static ENGINE* load_engine(const char *so_path, const char *sdf_lib_path) {
ENGINE_load_dynamic();
ENGINE *e = ENGINE_by_id("dynamic");
if (!e) {
fprintf(stderr, "Failed to get dynamic ENGINE\n");
return NULL;
}
if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", so_path, 0)) goto err;
if (!ENGINE_ctrl_cmd_string(e, "ID", "sdf", 0)) goto err;
if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) goto err;
if (!ENGINE_ctrl_cmd_string(e, "SDF_LIB_PATH", sdf_lib_path, 0)) goto err;
if (!ENGINE_init(e)) goto err;
return e;
err:
ENGINE_free(e);
return NULL;
}
static void test_sm4_cbc(void) {
unsigned char pt[32] = "abcdefghijklmnopqrstuvwxyz012345";
unsigned char ct[48] = {0};
unsigned char dt[48] = {0};
int outl = 0, totl = 0;
/* 加密 */
EVP_CIPHER_CTX *ectx = EVP_CIPHER_CTX_new();
if (!ectx) {
fprintf(stderr, "Encrypt ctx new failed\n");
exit(EXIT_FAILURE);
}
if (EVP_EncryptInit_ex(ectx, EVP_sm4_cbc(), g_engine, g_key16, g_iv16) != 1) {
fprintf(stderr, "EncryptInit failed\n");
EVP_CIPHER_CTX_free(ectx);
exit(EXIT_FAILURE);
}
if (EVP_EncryptUpdate(ectx, ct, &outl, pt, 32) != 1) {
fprintf(stderr, "EncryptUpdate failed\n");
EVP_CIPHER_CTX_free(ectx);
exit(EXIT_FAILURE);
}
totl = outl;
if (EVP_EncryptFinal_ex(ectx, ct + totl, &outl) != 1) {
fprintf(stderr, "EncryptFinal failed\n");
EVP_CIPHER_CTX_free(ectx);
exit(EXIT_FAILURE);
}
totl += outl;
if (totl != 48) {
fprintf(stderr, "CBC ciphertext length wrong\n");
EVP_CIPHER_CTX_free(ectx);
exit(EXIT_FAILURE);
}
EVP_CIPHER_CTX_free(ectx);
/* 解密 */
EVP_CIPHER_CTX *dctx = EVP_CIPHER_CTX_new();
if (!dctx) {
fprintf(stderr, "Decrypt ctx new failed\n");
exit(EXIT_FAILURE);
}
if (EVP_DecryptInit_ex(dctx, EVP_sm4_cbc(), g_engine, g_key16, g_iv16) != 1) {
fprintf(stderr, "DecryptInit failed\n");
EVP_CIPHER_CTX_free(dctx);
exit(EXIT_FAILURE);
}
if (EVP_DecryptUpdate(dctx, dt, &outl, ct, 48) != 1) {
fprintf(stderr, "DecryptUpdate failed\n");
EVP_CIPHER_CTX_free(dctx);
exit(EXIT_FAILURE);
}
totl = outl;
if (EVP_DecryptFinal_ex(dctx, dt + totl, &outl) != 1) {
fprintf(stderr, "DecryptFinal failed\n");
EVP_CIPHER_CTX_free(dctx);
exit(EXIT_FAILURE);
}
totl += outl;
EVP_CIPHER_CTX_free(dctx);
if (totl != 32 || memcmp(dt, pt, 32) != 0) {
fprintf(stderr, "CBC round-trip failed\n");
exit(EXIT_FAILURE);
}
printf("SM4-CBC encryption/decryption: OK\n");
}
int main(void) {
printf("Loading ENGINE...\n");
g_engine = load_engine(ENGINE_SO_PATH, SDF_LIB_PATH);
if (!g_engine) {
fprintf(stderr, "Engine load failed\n");
return EXIT_FAILURE;
}
printf("Engine loaded.\n");
test_sm4_cbc();
ENGINE_free(g_engine);
printf("SM4-CBC test passed.\n");
return EXIT_SUCCESS;
}