开发者
资源
文档评分
获取效率
正确性
完整性
易理解
在线提单
论坛求助

SM4-GCM算法调用示例

保存以下代码至sm4_gcm_demo.c,编译运行。

gcc -o sm4_gcm_demo sm4_gcm_demo.c -lssl -lcrypto -ldl
./sm4_gcm_demo
/**
 * sm4_gcm_demo.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/obj_mac.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 const EVP_CIPHER* get_sm4_gcm(void) {
    int nid = OBJ_sn2nid("sm4-gcm");
    if (nid == NID_undef) return NULL;
    return ENGINE_get_cipher(g_engine, nid);
}
static void test_sm4_gcm(void) {
    const EVP_CIPHER *gcm = get_sm4_gcm();
    if (!gcm) {
        fprintf(stderr, "SM4-GCM not supported by ENGINE\n");
        exit(EXIT_FAILURE);
    }
    const unsigned char aad[] = "additional authenticated data";
    unsigned char pt[32], ct[32], dt[32];
    unsigned char tag[16];
    int outl = 0, totl = 0;
    for (int i = 0; i < 32; i++) pt[i] = (unsigned char)(i + 0x10);
    /* 加密 */
    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, gcm, g_engine, g_key16, g_iv16) != 1) {
        fprintf(stderr, "EncryptInit failed\n");
        EVP_CIPHER_CTX_free(ectx);
        exit(EXIT_FAILURE);
    }
    int len;
    if (EVP_EncryptUpdate(ectx, NULL, &len, aad, sizeof(aad)) != 1) {
        fprintf(stderr, "Set AAD 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 (EVP_CIPHER_CTX_ctrl(ectx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) {
        fprintf(stderr, "Get tag failed\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, gcm, g_engine, g_key16, g_iv16) != 1) {
        fprintf(stderr, "DecryptInit failed\n");
        EVP_CIPHER_CTX_free(dctx);
        exit(EXIT_FAILURE);
    }
    if (EVP_CIPHER_CTX_ctrl(dctx, EVP_CTRL_GCM_SET_TAG, 16, tag) != 1) {
        fprintf(stderr, "Set tag failed\n");
        EVP_CIPHER_CTX_free(dctx);
        exit(EXIT_FAILURE);
    }
    if (EVP_DecryptUpdate(dctx, NULL, &len, aad, sizeof(aad)) != 1) {
        fprintf(stderr, "Set AAD (dec) failed\n");
        EVP_CIPHER_CTX_free(dctx);
        exit(EXIT_FAILURE);
    }
    if (EVP_DecryptUpdate(dctx, dt, &outl, ct, 32) != 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 (authentication may have 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, "GCM round-trip failed\n");
        exit(EXIT_FAILURE);
    }
    printf("SM4-GCM with AAD: 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_gcm();
    ENGINE_free(g_engine);

    printf("SM4-GCM test passed.\n");
    return EXIT_SUCCESS;
}