讲师中心 微信公众号
AI工具推荐 视频效率加速

C++如何调用SM2/SM3/SM4国密算法?(GMSSL或自研实现)

星宇酱_8680

星宇酱_8680

发布时间:2026-03-05 14:56:02

|

1313人浏览过

|

来源于php中文网

原创

使用GMSSL的C++接口需手动封装OpenSSL兼容层,严格遵循其内存管理、数据类型(unsigned char*)及EVP接口规范,避免常见错误如未检查错误码、IV复用、padding缺失等。

c++如何调用sm2/sm3/sm4国密算法?(gmssl或自研实现)

用 GMSSL 的 C++ 接口调 SM2/SM3/SM4,得自己补 OpenSSL 兼容层

GMSSL 官方只提供 C 接口和命令行工具,C++ 直接 extern "C" 包一层就能用,但别指望有 std::string 友好封装。它的底层就是 OpenSSL 1.1.1 的 fork,所以函数签名、内存管理逻辑和 OpenSSL 高度一致——这意味着你得手动处理 BIO、EVP_MD_CTX、SM4_KEY 这类结构体的生命周期。

常见错误现象:SM2_sign 返回 NULL 但没检查 ERR_get_error();SM4_encrypt 输出乱码是因为没初始化 SM4_KEY 或 IV 复用;SM3_Update 传了 std::string::data() 但长度传了 .size() + 1(多算了 null terminator)。

  • 所有密钥、IV、明文/密文缓冲区必须是 unsigned char*,别传 char*(符号扩展可能翻车)
  • SM2_do_sign 要求私钥是 EC_KEY* 格式,不能直接喂 PEM 字符串——得先用 PEM_read_bio_ECPrivateKey 解析
  • SM4 的 ECB 模式不校验 padding,但 CBC 模式必须手动补 PKCS#7,GMSSL 不帮你做

SM3 哈希计算最简路径:绕过 BIO,直用 EVP 接口

别碰 SM3_Init/SM3_Update 这套老接口,它不支持多线程且容易忘调 SM3_Final。直接上 OpenSSL 风格的 EVP_MD 体系,GMSSL 已注册 "sm3" 算法名。

使用场景:计算文件摘要、生成数字信封摘要、拼接签名原文前的哈希预处理。

立即学习“C++免费学习笔记(深入)”;

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sm3(), nullptr);
EVP_DigestUpdate(ctx, data, len);
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int md_len;
EVP_DigestFinal_ex(ctx, md, &md_len);
EVP_MD_CTX_free(ctx);
  • 必须用 EVP_sm3(),不是 EVP_sha256() 那种宏——GMSSL 把它编译进去了,但不会出现在 OpenSSL_add_all_algorithms() 里
  • md_len 固定为 32,但务必用输出参数接收,别硬写 sizeof(md)
  • 如果对同一段数据反复哈希,复用 ctx 前必须调 EVP_DigestInit_ex 重置,否则结果错

SM2 签名验签时,公钥格式和 ASN.1 编码是最大坑点

GMSSL 的 SM2_do_verify 要求公钥是 EC_KEY*,且曲线必须是 SM2_P256v1(即 OBJ_sm2)。但你从 Java 或浏览器拿到的 SM2 公钥,大概率是 DER 编码的 SubjectPublicKeyInfo,不是裸的 EC_POINT 坐标。

常见错误现象:EC_KEY_set_public_key_affine_coordinates 返回 0;SM2_do_verify 返回 -1 且 ERR_reason_error_string(ERR_get_error()) 显示 EC_R_INVALID_ENCODING。

  • 别手写坐标解析——用 d2i_EC_PUBKEY 从 DER 数据构造 EC_KEY*,不是 d2i_ECParameters
  • PEM 格式的公钥要先用 PEM_read_bio_PUBKEY,不是 PEM_read_bio_EC_PUBKEY(后者只认 OpenSSL 原生 EC key PEM)
  • SM2 签名结果是 ASN.1 序列(r,s),长度固定 64 字节,但某些硬件模块返回的是拼接的 r||s(无 ASN.1 头),此时得用 SM2_SIG_recover_r_s 手动拆

自研 SM4 实现?除非你审计过加解密轮函数和 S-Box

网上能找到的 C++ SM4 实现,90% 在 S-Box 查表时用 int 当索引却没做范围检查,或在密钥扩展中把 uint32_t 移位当 int 处理导致符号扩展。更隐蔽的问题是:部分实现把 SM4 的“加密”和“解密”轮函数写反了(国密标准里加解密结构对称但子密钥顺序相反)。

性能影响:纯查表实现比 GMSSL 的 AES-NI 加速版本慢 3–5 倍;移动端 ARM 上若没用 NEON 指令,吞吐量可能不到 1MB/s。

  • 真要自研,必须拿国密局发布的《SM4 分组密码算法》附录 A 测试向量逐字节比对,尤其关注第 32 轮输出和最终异或
  • 别信“兼容 OpenSSL EVP 接口”的封装库——它们多数只是把 GMSSL 的 C 函数包了一层 class,没解决线程安全问题
  • Android NDK 下链接 GMSSL,记得加 -lssl -lcrypto -lgmssl,且 libgmssl.so 必须和 libcrypto.so 版本对齐,否则 dlopen 失败

SM2 密钥协商、SM4 的 GCM 模式、SM3 的 HMAC 变种这些进阶用法,文档极少,出问题基本靠翻 GMSSL 的 test 目录源码。别省这步。

热门AI工具

更多
立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2931

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

534

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

502

2026.02.12

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6299

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

549

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1678

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1738

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2664

2023.09.04

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

20

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 0.1万人学习

C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn