简介:这份资源是面向Windows平台C/C++开发者的国密算法支撑库GMSSL 2.5.4编译成品,适合需要在项目中集成SM2、SM3、SM4等国密算法、又不想自行折腾编译环境的工程师直接取用。压缩包共110个文件,约5.5MB,其中95个.h头文件覆盖ssl、evp、ec、obj_mac等接口声明,4个.dll与2个.lib提供libcrypto、libssl等动态与静态链接支持,另附pdb调试符号、gmssl.exe命令行工具及applink.c等示例源码,结构完整、开箱即用。目前已有1283人学习下载。相比网上动辄需要积分兑换的版本,该包由作者自行编译并免费分享,省去了源码配置与编译环节,读者可直接将头文件与库文件接入现有工程,快速完成国密算法的调用与验证,也便于对照头文件理解各模块的接口组织方式。
1. 拿到 GMSSL 2.5.4 Windows 包,先别急着解压
如果你正在做国密改造,大概率绕不开 GMSSL 这个名字。它是一套开源的国密算法支撑库,把 SM2、SM3、SM4、SM9 以及国密双证书体系这套东西用 C 语言实现出来,同时提供命令行工具和开发接口。你手上这个GMSSL.zip是 Windows 版本 2.5.4,解压后能直接跑,不需要自己从源码编译。这件事对很多做后端、嵌入式、客户端安全模块的工程师来说,省掉的是 OpenSSL 交叉编译那一整套折腾。
它适合谁?第一类是做接口联调的人,需要快速生成 SM2 密钥对、算 SM3 摘要、跑 SM4 加解密来验证对方系统;第二类是做国密合规改造的开发者,要把国密能力嵌进自己的 C/C++ 工程;第三类是做测试和运维的,需要一把趁手的命令行工具来构造国密测试数据。不适合谁?如果你只是想在浏览器里点两下做国密 TLS 握手,这个包不是给你用的,它是底层库和命令行工具,不是图形化产品。
我见过太多人拿到压缩包,双击解压,看到一堆 exe 和 dll,然后愣住——不知道从哪下手。这篇就按我实际拆包的顺序,把目录结构、命令行用法、开发接口、编译链接、踩坑点全部走一遍。你照着做,半小时内能让 SM2 签名验签跑通。
2. 拆开目录看结构:bin、lib、include 各管什么
2.1 目录布局与文件职责
解压GMSSL.zip之后,根目录下通常能看到几个关键文件夹。不同打包方式可能略有差异,但核心结构是一致的。我一般先看这三处:
| 目录 | 内容 | 用途 |
|---|---|---|
bin/ | gmssl.exe及依赖 dll | 命令行工具,直接运行 |
lib/ | libgmssl.lib、libcrypto.lib等 | 静态/导入库,编译链接用 |
include/ | gmssl/头文件目录 | 开发时 include 用 |
certs/或test/ | 示例证书、测试脚本 | 验证环境是否正常 |
先确认bin/gmssl.exe能不能跑。打开 cmd 或 PowerShell,cd 到 bin 目录,执行:
gmssl version如果输出版本号类似GMSSL 2.5.4,说明运行时依赖没问题。如果报错缺 dll,大概率是 VC 运行库没装,或者 dll 不在同级目录。常见做法是把 bin 目录加到 PATH,或者直接把 dll 拷到 exe 旁边。
提示:Windows 下 dll 搜索顺序是先当前目录再 PATH,所以最稳的方式是 exe 和 dll 放一起,别乱挪。
2.2 命令行工具的能力边界
gmssl.exe是一个多合一工具,子命令覆盖了国密主要算法。执行gmssl help能看到完整列表。我常用的几类:
sm2:密钥生成、签名、验签、加解密sm3:摘要计算sm4:对称加解密rand:随机数生成cert:证书相关操作
这里有个容易翻车的点:GMSSL 的命令行参数风格和 OpenSSL 不完全一样,别拿 OpenSSL 的习惯硬套。比如生成 SM2 密钥,OpenSSL 是ecparam,GMSSL 直接sm2 -genkey。参数名也有差异,具体以gmssl sm2 -help的输出为准。
我一般会先跑一遍最小验证链路:生成密钥 → 签名 → 验签。这条链路通了,说明库本身没问题,后面再往工程里集成就有底了。
3. 命令行实操:SM2 签名验签与 SM4 加解密走一遍
3.1 SM2 密钥生成与签名验签
先建一个工作目录,比如D:\gmtest,把 gmssl.exe 和 dll 拷进去,或者直接用 bin 目录。下面这套命令我实测过,2.5.4 版本可用:
# 生成 SM2 私钥(PEM 格式) gmssl sm2 -genkey -out sm2_private.pem # 从私钥导出公钥 gmssl sm2 -pubout -in sm2_private.pem -out sm2_public.pem # 对文件做 SM3 摘要并签名,输出签名值 gmssl sm2 -sign -in message.txt -inkey sm2_private.pem -out message.sig # 用公钥验签 gmssl sm2 -verify -in message.txt -pubkey sm2_public.pem -sigfile message.sig逻辑说明:-genkey生成的是符合国密规范的 SM2 密钥对,私钥 PEM 里包含曲线参数 OID。-sign默认先对输入做 SM3 摘要再签名,不是直接对原文签名,这一点和 ECDSA 的默认行为类似。-verify验签成功会输出Verify OK之类的提示,失败则报错。
参数说明:-in指定待处理文件,-inkey指定私钥,-pubkey指定公钥,-out指定输出。注意-sigfile是验签时指定签名文件的参数,别写成-in,否则会把签名文件当原文验,必然失败。
注意:SM2 签名结果默认是 DER 编码。如果你对接的系统要求裸 r||s 格式,需要额外转换,命令行工具不一定直接支持,得走开发接口。
3.2 SM4 加解密与 SM3 摘要
SM4 是对称算法,128 位密钥,128 位分组。命令行用法:
# 生成 16 字节随机密钥(hex 输出) gmssl rand -outlen 16 -hex -out sm4_key.hex # 用密钥加密文件(CBC 模式,需指定 IV) gmssl sm4 -encrypt -in plain.txt -out cipher.bin -key $(cat sm4_key.hex) -iv 00000000000000000000000000000000 # 解密 gmssl sm4 -decrypt -in cipher.bin -out plain_dec.txt -key $(cat sm4_key.hex) -iv 00000000000000000000000000000000 # SM3 摘要 gmssl sm3 -in plain.txt -out plain.sm3逻辑说明:SM4 加密前需要确定模式和填充。GMSSL 命令行默认可能是 CBC + PKCS7 填充,但不同版本行为可能有差异,建议用-help确认。IV 必须是 16 字节 hex,全零只是测试用,生产环境必须随机且每次不同。
参数说明:-key和-iv都接受 hex 字符串。$(cat sm4_key.hex)是 Linux 写法,Windows cmd 下需要先读出来再传,或者用 PowerShell 的Get-Content。这也是一个常见翻车点——Windows 和 Linux 的 shell 替换语法不同,别直接抄 Linux 脚本。
SM3 摘要输出是 hex 字符串,32 字节。你可以用它来校验文件完整性,或者作为签名前的摘要步骤。
3.3 用批处理串起验证流程
Windows 下我习惯写一个.bat把上面步骤串起来,方便反复验证:
@echo off set GMSSL=gmssl.exe %GMSSL% sm2 -genkey -out sm2_private.pem %GMSSL% sm2 -pubout -in sm2_private.pem -out sm2_public.pem echo test message > msg.txt %GMSSL% sm2 -sign -in msg.txt -inkey sm2_private.pem -out msg.sig %GMSSL% sm2 -verify -in msg.txt -pubkey sm2_public.pem -sigfile msg.sig echo Done. pause逻辑说明:这个脚本把密钥生成、签名、验签串成一条链路,跑完看到验签成功就说明环境 OK。参数没有额外变化,只是把命令写进批处理。注意echo test message > msg.txt会带换行符,签名和验签用的是同一个文件,所以没问题。
如果这一步失败,先检查 gmssl.exe 是否在当前目录或 PATH,再检查 dll 是否齐全。我遇到过因为缺libssl-1_1-x64.dll导致 exe 直接闪退的情况,用 Dependency Walker 或where命令排查。
4. 集成到 C/C++ 工程:头文件、库链接与接口调用
4.1 工程配置与链接参数
把 GMSSL 集成进自己的工程,核心是三件事:include 路径、库路径、链接库名。以 Visual Studio 为例,在项目属性里配置:
- C/C++ → 常规 → 附加包含目录:指向
include/目录 - 链接器 → 常规 → 附加库目录:指向
lib/目录 - 链接器 → 输入 → 附加依赖项:加入
libgmssl.lib(或对应版本的库名)
如果你用的是静态库,还需要注意运行库匹配(/MT vs /MD)。GMSSL 如果编译时用的是 /MT,你的工程也得用 /MT,否则会出现符号冲突或堆损坏。这个坑很隐蔽,现象是编译链接通过但运行崩溃。
代码里 include 头文件:
#include <gmssl/sm2.h> #include <gmssl/sm3.h> #include <gmssl/sm4.h>逻辑说明:GMSSL 的头文件按模块组织,sm2.h 里是 SM2 密钥、签名、加解密接口,sm3.h 是摘要,sm4.h 是对称算法。不要只 include 一个总头文件,2.5.4 版本没有统一的 gmssl.h 聚合头,按需引入。
4.2 SM2 签名接口调用示例
下面是一段最小可用的 SM2 签名代码,基于 GMSSL 的 C 接口:
#include <stdio.h> #include <string.h> #include <gmssl/sm2.h> #include <gmssl/sm3.h> int main(void) { SM2_KEY key; uint8_t dgst[32]; uint8_t sig[SM2_MAX_SIGNATURE_SIZE]; size_t siglen; // 生成密钥对 if (sm2_key_generate(&key) != 1) { printf("key gen failed\n"); return -1; } // 对消息做 SM3 摘要 const char *msg = "hello gmssl"; sm3_digest((uint8_t *)msg, strlen(msg), dgst); // 签名 if (sm2_sign(&key, dgst, sig, &siglen) != 1) { printf("sign failed\n"); return -1; } // 验签 if (sm2_verify(&key, dgst, sig, siglen) != 1) { printf("verify failed\n"); return -1; } printf("sign and verify ok, siglen=%zu\n", siglen); return 0; }逻辑说明:sm2_key_generate生成密钥对,内部包含私钥和公钥。sm3_digest对消息做摘要,输出 32 字节。sm2_sign对摘要签名,签名结果写入sig缓冲区,siglen返回实际长度。sm2_verify用同一密钥对验签。注意这里用的是同一个SM2_KEY结构,实际场景中验签方只有公钥,需要用sm2_key_get_public_key或从 PEM 加载公钥。
参数说明:SM2_MAX_SIGNATURE_SIZE是宏定义,保证缓冲区够大。sm2_sign的第二个参数是摘要值,不是原文,所以如果你要对原文签名,必须先自己做 SM3。这一点和命令行工具行为一致。
编译命令(MSVC):
cl test_sm2.c /I include /link /LIBPATH:lib libgmssl.lib如果报未解析符号,检查库名是否匹配,以及是否漏了依赖库(比如某些版本需要额外链接ws2_32.lib)。
4.3 SM4 接口与模式选择
SM4 的 C 接口稍微复杂一点,因为涉及模式和填充。GMSSL 提供sm4_encrypt和sm4_decrypt基础接口,以及 CBC 等模式的封装。常见做法是:
#include <gmssl/sm4.h> SM4_KEY sm4_key; uint8_t key[16] = {0}; uint8_t iv[16] = {0}; uint8_t in[16] = "1234567890abcdef"; uint8_t out[16]; sm4_set_encrypt_key(&sm4_key, key); sm4_cbc_encrypt(&sm4_key, iv, in, 16, out);逻辑说明:sm4_set_encrypt_key设置加密密钥,sm4_cbc_encrypt做 CBC 模式加密。注意 CBC 需要 IV,且加密和解密的 IV 要一致。填充需要自己处理,GMSSL 底层接口不自动填充,这是和命令行工具的一个差异。
参数说明:key必须是 16 字节,iv也是 16 字节。in和out长度必须是 16 的倍数,否则需要自己补位。生产环境建议用 PKCS7 填充,并确保解密后去掉填充。
注意:底层接口不做填充和长度校验,传错长度可能读越界。这是血泪经验,别问我怎么知道的。
5. 避坑与排查:那些让你怀疑人生的报错
5.1 现象:gmssl.exe 双击闪退,命令行报缺 dll
原因:Windows 下 exe 依赖的 dll 不在搜索路径。GMSSL 的 bin 目录里通常带了 dll,但如果你把 exe 单独拷出来,dll 就找不到了。
解决:把 bin 目录下所有 dll 和 exe 放同一目录,或者把 bin 目录加到系统 PATH。用where gmssl确认找到的是哪个。如果还不行,装一下 VC++ 运行库。
5.2 现象:SM2 验签失败,但签名命令没报错
原因:最常见的是签名和验签用的不是同一个摘要,或者验签时-sigfile参数写错,把签名文件当成了原文。另一个可能是公钥和私钥不匹配。
解决:先确认sm2_public.pem是从sm2_private.pem导出的。再确认验签命令里-in是原文,-sigfile是签名文件。如果还失败,用gmssl sm2 -help看参数名是否和你写的一致,不同版本参数可能有微调。
5.3 现象:集成到工程后链接报未解析符号
原因:库名不对,或者运行库不匹配(/MT vs /MD),或者漏了依赖库。
解决:先用dumpbin /symbols libgmssl.lib | findstr sm2_sign确认符号在库里。再检查工程运行库设置是否和库一致。如果库是 /MT 编译的,工程也改成 /MT。漏依赖库的话,看报错符号属于哪个模块,补上对应 lib。
5.4 现象:SM4 解密出来是乱码
原因:IV 不一致,或者填充方式不对,或者密钥传错。
解决:确认加密和解密用的 key、iv 完全一致。如果命令行加密、代码解密,要确认命令行默认的填充方式和代码里的是否一致。最稳的方式是两边都用同一套接口,或者都用命令行。
5.5 现象:Windows 下批处理里$(cat xxx)不生效
原因:那是 Linux shell 的语法,Windows cmd 不支持。
解决:用set /p读文件,或者直接用 PowerShell。比如set /p KEY=<sm4_key.hex然后%KEY%。别直接抄 Linux 脚本,这是跨平台最常见的翻车点。
6. 进阶技巧:用 SM2 双证书体系做一次完整链路验证
国密改造里有一个绕不开的概念:双证书体系,即签名证书和加密证书分开。GMSSL 2.5.4 的命令行工具支持证书相关操作,但文档不多,我摸索出一套验证链路,分享给你。
先准备两套 SM2 密钥,分别作为签名密钥和加密密钥:
gmssl sm2 -genkey -out sign_key.pem gmssl sm2 -genkey -out enc_key.pem然后生成自签名证书(测试用,生产环境走 CA):
gmssl cert -selfsign -key sign_key.pem -out sign_cert.pem -days 365 gmssl cert -selfsign -key enc_key.pem -out enc_cert.pem -days 365逻辑说明:cert -selfsign用私钥自签名生成证书,-days指定有效期。这里生成的证书是国密 SM2 证书,不是 RSA 证书。你可以用gmssl cert -text -in sign_cert.pem查看证书内容,确认公钥算法是 SM2。
接下来做一次完整的签名+加密链路:发送方用自己的签名私钥对消息签名,用接收方的加密公钥对消息加密;接收方用发送方签名公钥验签,用自己的加密私钥解密。
# 发送方:签名 gmssl sm2 -sign -in msg.txt -inkey sign_key.pem -out msg.sig # 发送方:用接收方加密公钥加密 gmssl sm2 -encrypt -in msg.txt -pubkey enc_key.pem -out msg.enc # 接收方:验签 gmssl sm2 -verify -in msg.txt -pubkey sign_key.pem -sigfile msg.sig # 接收方:解密 gmssl sm2 -decrypt -in msg.enc -inkey enc_key.pem -out msg.dec参数说明:-encrypt和-decrypt是 SM2 加解密子命令,和签名共用密钥结构但用途不同。注意加密用的是接收方公钥,解密用的是接收方私钥。签名和验签用的是发送方密钥对。这四个命令跑通,说明双证书链路基本可用。
这里有个细节:SM2 加密结果包含 C1、C2、C3 三部分,不同系统对这三部分的排列顺序和编码格式要求可能不同。GMSSL 默认输出是 DER 编码,如果你对接的系统要求 C1C3C2 或 C1C2C3 裸拼接,需要自己转换。我一般会写一个小脚本来做格式适配,而不是改库。
还有一个验证技巧:用gmssl sm3对解密后的文件和原文件分别算摘要,对比是否一致。这比肉眼比对内容可靠得多。
gmssl sm3 -in msg.txt -out msg.sm3 gmssl sm3 -in msg.dec -out msg_dec.sm3 fc msg.sm3 msg_dec.sm3fc是 Windows 的文件比较命令,输出无差异就说明解密正确。
从那以后我每次拿到新的国密库版本,都强制走一遍「生成密钥 → 签名验签 → 加密解密 → 摘要比对」这条最小链路,确认环境没问题再往工程里集成。这个习惯帮我省掉了至少三次在集成阶段才发现库本身有问题的尴尬。希望帮到你。
本文还有配套的精品资源,点击获取