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;
}