Visual Studio输出一个SM4算法加解密的动态库(本文使用GMSSL)

1.基本信息简介

静态库与动态库编程基础

静态库(.lib)在编译时被链接到程序中,动态库(.dll)在运行时加载。动态库的优势在于可减少程序体积,便于模块化更新。

常用加密算法简介

对称加密(如AES、SM4)使用相同密钥加解密,非对称加密(如RSA)使用公私钥对。哈希算法(如SHA-256)用于数据完整性验证。

SM4算法原理

SM4是中国国家密码管理局发布的分组加密算法,采用128位密钥和分组长度。算法结构包括32轮非线性迭代和反序解密。

2.安装 GMSSL

安装教程参考这篇Windows环境下GMSSL的安装与编译的超详细教程_gmssl安装-优快云博客

3.使用Visual Studio输出动态库(使用lib方式引入)

1.新建项目

  • 打开Visual Studio,选择“创建新项目”。

  • 在项目类型中选择“动态链接库(DLL)”,然后点击“下一步”。

  • 填写项目名称等信息,选择合适的存储位置,然后点击“创建”按钮

2.使用lib方式引入gmssl动态库

头文件(sm4_dll.h)

#ifndef SM4_DLL_H
#define SM4_DLL_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#define SM4_DLL_API __declspec(dllexport)
#else
#define SM4_DLL_API
#endif

    // SM4 加密函数
    SM4_DLL_API int sm4_encrypt_dll(const unsigned char* key, const unsigned char* plaintext, unsigned char* ciphertext);

    // SM4 解密函数
    SM4_DLL_API int sm4_decrypt_dll(const unsigned char* key, const unsigned char* ciphertext, unsigned char* plaintext);

#ifdef __cplusplus
}
#endif

#endif // SM4_DLL_H

cpp文件(sm4_dll.cpp)

#include "pch.h"
#include "sm4_dll.h"
#include <gmssl/sm4.h>

// SM4 加密函数
extern "C" SM4_DLL_API int sm4_encrypt_dll(const unsigned char* key, const unsigned char* plaintext, unsigned char* ciphertext)
{
    SM4_KEY sm4_key; // 创建 SM4 密钥结构
    sm4_set_encrypt_key(&sm4_key, key); // 设置加密密钥
    sm4_encrypt(&sm4_key, plaintext, ciphertext); // 调用 GmSSL 加密函数
    return 0; // 返回成功
}

// SM4 解密函数
extern "C" SM4_DLL_API int sm4_decrypt_dll(const unsigned char* key, const unsigned char* ciphertext, unsigned char* plaintext)
{
    SM4_KEY sm4_key; // 创建 SM4 密钥结构
    sm4_set_decrypt_key(&sm4_key, key); // 设置解密密钥
    sm4_encrypt(&sm4_key, ciphertext, plaintext); // 调用 GmSSL 的解密函数,注意这里使用的是 sm4_encrypt
    return 0; // 返回成功
}

Visual Studio配置

在VC项目中,右键单击“解决方案资源管理器”中的项目名称,选择“属性”

在“属性页”中,点击“VC++目录”,分别在“包含目录”和“库目录”中添加GMSSL的include目录和lib目录路径。

在VC项目中选择“生成”->“生成解决方案”。

如果没有错误,会在项目文件夹的Debug或Release目录下生成一个DLL文件。

3.测试DLL

  • 创建一个新的VC项目,用于测试刚才生成的DLL。

  • 在项目中包含之前创建的DLL的头文件和库文件。

  • 编写测试代码,调用DLL中的SM4加密和解密函数,验证其正确性

testsm4dll.cpp文件

// main.c
#include <windows.h>
#include <stdio.h>
#include <string.h>

// 定义函数指针类型(使用__stdcall)
// 修改为__cdecl(与DLL实际调用约定匹配)
typedef int(__cdecl* SM4_Encrypt_Func)(const unsigned char*, const unsigned char*, unsigned char*);
typedef int(__cdecl* SM4_Decrypt_Func)(const unsigned char*, const unsigned char*, unsigned char*);

#define SM4_BLOCK_SIZE 16

int main() {
    // 加载DLL
    HINSTANCE hDLL = LoadLibrary(L"SM4Lib.dll");
    if (!hDLL) {
        printf("无法加载DLL!\n");
        return 1;
    }

    // 获取函数指针
    SM4_Encrypt_Func pSM4_Encrypt = (SM4_Encrypt_Func)GetProcAddress(hDLL, "sm4_encrypt_dll");
    SM4_Decrypt_Func pSM4_Decrypt = (SM4_Decrypt_Func)GetProcAddress(hDLL, "sm4_decrypt_dll");

    if (!pSM4_Encrypt || !pSM4_Decrypt) {
        DWORD error = GetLastError();
        printf("无法获取函数地址!错误代码: %lu\n", error);
        FreeLibrary(hDLL);
        return 1;
    }

    // 测试数据
    const unsigned char key[SM4_BLOCK_SIZE] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
    };

    unsigned char input[SM4_BLOCK_SIZE] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
    };

    unsigned char encrypted[SM4_BLOCK_SIZE] = { 0 };
    unsigned char decrypted[SM4_BLOCK_SIZE] = { 0 };

    // 使用DLL进行加密
    int encryptResult = pSM4_Encrypt(key, input, encrypted);
    if (encryptResult != 0) {
        printf("加密失败!返回码: %d\n", encryptResult);
        FreeLibrary(hDLL);
        return 1;
    }

    printf("加密后:");
    for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {
        printf("%02x ", encrypted[i]);
    }
    printf("\n");

    // 使用DLL进行解密
    int decryptResult = pSM4_Decrypt(key, encrypted, decrypted);
    if (decryptResult != 0) {
        printf("解密失败!返回码: %d\n", decryptResult);
        FreeLibrary(hDLL);
        return 1;
    }

    printf("解密后:");
    for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {
        printf("%02x ", decrypted[i]);
    }
    printf("\n");

    // 验证解密结果
    if (memcmp(input, decrypted, SM4_BLOCK_SIZE) == 0) {
        printf("加密和解密成功!\n");
    }
    else {
        printf("加密和解密失败!\n");
    }

    // 卸载DLL
    FreeLibrary(hDLL);

    return 0;
}

4.使用Visual Studio输出动态库(使用dll方式引入)

 

头文件(sm4_dll.h)

#pragma once
#ifdef SM4_DLL_EXPORTS
#define SM4_DLL_API __declspec(dllexport)
#else
#define SM4_DLL_API __declspec(dllimport)
#endif

extern "C" {
    // SM4加密函数
    SM4_DLL_API int SM4_Encrypt(const unsigned char* plaintext, int plaintext_len,
        const unsigned char* key, unsigned char* ciphertext);

    // SM4解密函数
    SM4_DLL_API int SM4_Decrypt(const unsigned char* ciphertext, int ciphertext_len,
        const unsigned char* key, unsigned char* plaintext);
}

cpp文件(sm4_dll.cpp)

#include "pch.h"
#include "sm4_dll.h"
#include <windows.h>
#include <iostream>

// 定义GMSSL函数指针类型
typedef void(__cdecl* SM4_SET_ENCRYPT_KEY)(void* sm4_key, const unsigned char* key);
typedef void(__cdecl* SM4_SET_DECRYPT_KEY)(void* sm4_key, const unsigned char* key);
typedef void(__cdecl* SM4_ENCRYPT)(void* sm4_key, const unsigned char* input, unsigned char* output);

// 动态加载的GMSSL函数指针
static HINSTANCE hGmSSL = NULL;
static SM4_SET_ENCRYPT_KEY pSm4SetEncryptKey = NULL;
static SM4_SET_DECRYPT_KEY pSm4SetDecryptKey = NULL;
static SM4_ENCRYPT pSm4Encrypt = NULL;

// 初始化GMSSL库
bool InitGmSSL() {
    if (hGmSSL) return true;

    // 加载gmssl.dll
    hGmSSL = LoadLibraryA("gmssl.dll");
    if (!hGmSSL) {
        std::cerr << "无法加载gmssl.dll,错误代码: " << GetLastError() << std::endl;
        return false;
    }

    // 获取GMSSL函数地址
    pSm4SetEncryptKey = (SM4_SET_ENCRYPT_KEY)GetProcAddress(hGmSSL, "sm4_set_encrypt_key");
    pSm4SetDecryptKey = (SM4_SET_DECRYPT_KEY)GetProcAddress(hGmSSL, "sm4_set_decrypt_key");
    pSm4Encrypt = (SM4_ENCRYPT)GetProcAddress(hGmSSL, "sm4_encrypt");

    if (!pSm4SetEncryptKey || !pSm4SetDecryptKey || !pSm4Encrypt) {
        std::cerr << "无法获取GMSSL函数地址" << std::endl;
        FreeLibrary(hGmSSL);
        hGmSSL = NULL;
        return false;
    }

    return true;
}

// 清理GMSSL库
void CleanupGmSSL() {
    if (hGmSSL) {
        FreeLibrary(hGmSSL);
        hGmSSL = NULL;
        pSm4SetEncryptKey = NULL;
        pSm4SetDecryptKey = NULL;
        pSm4Encrypt = NULL;
    }
}

// SM4加密函数
extern "C" __declspec(dllexport) int __cdecl SM4_Encrypt(const unsigned char* plaintext, int plaintext_len,
    const unsigned char* key, unsigned char* ciphertext) {
    if (!InitGmSSL()) {
        return -1; // DLL加载失败
    }

    // 分配SM4密钥结构体内存
    void* sm4_key = malloc(128); // SM4密钥结构体大小应为128字节
    if (!sm4_key) {
        return -2; // 内存分配失败
    }

    // 设置加密密钥
    pSm4SetEncryptKey(sm4_key, (const unsigned char*)key);

    // 执行加密
    for (int i = 0; i < plaintext_len; i += 16) {
        int len = (plaintext_len - i) > 16 ? 16 : (plaintext_len - i);
        pSm4Encrypt(sm4_key, (const unsigned char*)(plaintext + i), (unsigned char*)(ciphertext + i));
    }

    // 释放密钥结构体内存
    free(sm4_key);

    return 0; // 操作成功
}

// SM4解密函数
extern "C" __declspec(dllexport) int __cdecl SM4_Decrypt(const unsigned char* ciphertext, int ciphertext_len,
    const unsigned char* key, unsigned char* plaintext) {
    if (!InitGmSSL()) {
        return -1; // DLL加载失败
    }

    // 分配SM4密钥结构体内存
    void* sm4_key = malloc(128); // SM4密钥结构体大小应为128字节
    if (!sm4_key) {
        return -2; // 内存分配失败
    }

    // 设置解密密钥
    pSm4SetDecryptKey(sm4_key, (const unsigned char*)key);

    // 执行解密
    for (int i = 0; i < ciphertext_len; i += 16) {
        int len = (ciphertext_len - i) > 16 ? 16 : (ciphertext_len - i);
        pSm4Encrypt(sm4_key, (const unsigned char*)(ciphertext + i), (unsigned char*)(plaintext + i));
    }

    // 释放密钥结构体内存
    free(sm4_key);

    return 0; // 操作成功
}

//BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
//    switch (ul_reason_for_call) {
//    case DLL_PROCESS_DETACH:
//        CleanupGmSSL();
//        break;
//    }
//    return TRUE;
//}

在VC项目中选择“生成”->“生成解决方案” 

如果没有错误,会在项目文件夹的Debug或Release目录下生成一个DLL文件。

测试DLL

  • 创建一个新的VC项目,用于测试刚才生成的DLL。

  • 在项目中包含之前创建的DLL的头文件和库文件。

  • 编写测试代码,调用DLL中的SM4加密和解密函数,验证其正确性

testSM4Lib2.cpp文件

#include <windows.h>
#include <stdio.h>
#include <string.h>

#define SM4_BLOCK_SIZE 16

int main() {
    // 加载DLL
    HINSTANCE hDLL = LoadLibrary(L"SM4Lib2.dll");
    if (!hDLL) {
        printf("无法加载DLL!\n");
        return 1;
    }

    // 获取函数地址
    typedef int(__cdecl* SM4_Encrypt_Func)(const unsigned char*, int, const unsigned char*, unsigned char*);
    typedef int(__cdecl* SM4_Decrypt_Func)(const unsigned char*, int, const unsigned char*, unsigned char*);

    SM4_Encrypt_Func pSM4_Encrypt = (SM4_Encrypt_Func)GetProcAddress(hDLL, "SM4_Encrypt");
    SM4_Decrypt_Func pSM4_Decrypt = (SM4_Decrypt_Func)GetProcAddress(hDLL, "SM4_Decrypt");

    if (!pSM4_Encrypt || !pSM4_Decrypt) {
        DWORD error = GetLastError();
        printf("无法获取函数地址!错误代码: %lu\n", error);
        FreeLibrary(hDLL);
        return 1;
    }

    // 定义密钥和输入数据
    const unsigned char key[SM4_BLOCK_SIZE] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
    };

    unsigned char input[SM4_BLOCK_SIZE] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
    };

    unsigned char encrypted[SM4_BLOCK_SIZE] = { 0 };
    unsigned char decrypted[SM4_BLOCK_SIZE] = { 0 };

    // 调用DLL进行加密
    int encryptResult = pSM4_Encrypt(input, SM4_BLOCK_SIZE, key, encrypted);
    if (encryptResult != 0) {
        printf("加密失败!错误代码: %d\n", encryptResult);
        FreeLibrary(hDLL);
        return 1;
    }

    printf("加密结果:");
    for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {
        printf("%02x ", encrypted[i]);
    }
    printf("\n");

    // 调用DLL进行解密
    int decryptResult = pSM4_Decrypt(encrypted, SM4_BLOCK_SIZE, key, decrypted);
    if (decryptResult != 0) {
        printf("解密失败!错误代码: %d\n", decryptResult);
        FreeLibrary(hDLL);
        return 1;
    }

    printf("解密结果:");
    for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {
        printf("%02x ", decrypted[i]);
    }
    printf("\n");

    // 验证解密结果
    if (memcmp(input, decrypted, SM4_BLOCK_SIZE) == 0) {
        printf("加密解密成功!\n");
    }
    else {
        printf("加密解密失败!\n");
    }

    // 卸载DLL
    FreeLibrary(hDLL);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值