️️️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践20241212
🛡️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践
✨ 引言
在当下的数据安全环境中,SM4作为中国国家密码算法的代表性选择,被广泛应用于金融、通信和政府领域。然而,在实际开发中,即便是开源加密库也可能隐藏深层次的问题,开发者常常需要对其功能和实现逻辑进行严格审查。最近,我在使用 gmssl 库实现 SM4 加密算法时,因填充逻辑问题陷入了困境。经过深入排查与修复,我不仅解决了问题,本文记录了一次真实的调试经历,揭示了如何高效定位并修复开源加密库gmssl中的潜在bug,还总结了一些通用的代码实践和调试经验。
🎯 本文要点:
- 揭示 gmssl 填充问题的根本原因。
- 提供填充问题的修复方法与多种实现风格。
- 分享 SM4 加解密的高效实现与最佳实践。
无论你是初学者还是资深开发者,相信这篇文章都能对你有所启发。

🛠️ 问题背景
🔑 关于 gmssl 库与 SM4 算法
gmssl 是一款支持国密标准的开源加密库,而 SM4 算法是其中的核心对称加密算法,应用场景广泛:
- 数据保护:如金融交易数据。
- 通信安全:如内网通信。
- 身份验证:如国密 HTTPS。
💡 填充模式:
- PKCS7 填充:主流且成熟,适合通用场景。
- ZERO 填充:用于固定长度数据流,但对边界场景要求更高。
❌ 遇到的问题
在调用 gmssl 解密时,程序报错如下:
TypeError: 'int' object is not iterable
🕵️ 问题定位
错误来自 gmssl 的填充移除函数 zero_unpadding:
zero_unpadding = lambda data, i=1: data[:-i] if data[-i] == 0 else i + 1
⚠️ 问题核心:
当数据未包含零填充时,data[-i] != 0,函数直接返回了整数 i + 1,而非预期的字节列表,导致后续处理失败。
🛠️ 修复方案
🚀 重新设计 zero_unpadding 函数
方法 1️⃣:普通函数实现
def zero_unpadding(data: list) -> list:"""Remove ZERO padding from decrypted dataArgs:data: List of bytes with ZERO paddingReturns:List of bytes with padding removedExamples:[1,2,3,0,0,0] -> [1,2,3][1,2,0,3,0,0] -> [1,2,0,3]"""if not data:return datafor i in range(len(data) - 1, -1, -1):if data[i] != 0:return data[:i + 1]return []```
我们设计了一组测试用例,覆盖常见场景:
```python
def test_zero_unpadding():"""测试零填充移除函数的各种情况"""test_data = [([1, 2, 3, 0, 0, 0], [1, 2, 3]), # 标准情况:末尾有零填充([1, 2, 3], [1, 2, 3]), # 无填充([0, 0, 0], []), # 全零([], []), # 空列表([1, 2, 0, 3, 0, 0], [1, 2, 0, 3]), # 中间有零([0, 1, 2, 0, 0], [0, 1, 2]), # 开头有零([1, 0, 2, 0, 0], [1, 0, 2]), # 中间和末尾都有零([255, 0, 0, 0], [255]), # 大数值测试]for input_data, expected in test_data:result = zero_unpadding(input_data)print(f"Input: {input_data}")print(f"Expected: {expected}")print(f"Got: {result}")assert result == expected, f"Test failed: expected {expected}, got {result}"print("✓ Test passed\n")# 运行测试
try:test_zero_unpadding()print("All tests passed successfully! 🎉")
except AssertionError as e:print(f"Test failed: {e}")
✅ 测试结果
/opt/anaconda3/envs/kids_tutor_env/bin/python /Users/xyl/Documents/git_src/kids-tutor-and-efficiency-scripts/study_md5/test.py
Input: [1, 2, 3, 0, 0, 0]
Expected: [1, 2, 3]
Got: [1, 2, 3]
✓ Test passedInput: [1, 2, 3]
Expected: [1, 2, 3]
Got: [1, 2, 3]
✓ Test passedInput: [0, 0, 0]
Expected: []
Got: []
✓ Test passedInput: []
Expected: []
Got: []
✓ Test passedInput: [1, 2, 0, 3, 0, 0]
Expected: [1, 2, 0, 3]
Got: [1, 2, 0, 3]
✓ Test passedInput: [0, 1, 2, 0, 0]
Expected: [0, 1, 2]
Got: [0, 1, 2]
✓ Test passedInput: [1, 0, 2, 0, 0]
Expected: [1, 0, 2]
Got: [1, 0, 2]
✓ Test passedInput: [255, 0, 0, 0]
Expected: [255]
Got: [255]
✓ Test passedAll tests passed successfully! 🎉进程已结束,退出代码为 0
结果汇总
所有测试用例都通过了,这证明我们的 zero_unpadding 函数完全符合预期。让我们总结一下测试覆盖的场景:
- 1.标准填充场景:[1,2,3,0,0,0]>[1,2,3]
验证正常的未尾零填充移除 - 2.无填充场景:[1,2,3]>[1,2,3]验证对无填充数据的正确处理
- 3.全零场景:[0,0,0]→>[]验证极端情况:全是填充
- 4.空列表场景:[]>[]
验证边界情况:空输入 - 5.中间包含零场景:[1,2,0,3,0,0]>[1,2,0,3]验证保留数据中的有效零值
- 6.开头包含零场景:[0,1,2,0,0]>[0,1,2]
验证保留开头的有效零值 - 7.混合零场景:[1,0,2,0,0]>[1,0,2]验证同时处理有效零和填充零
- 8.大值测试:[255,0,0,0]>[255]
验证对大数值的处理
这些测试结果表明该实现:
✅ 正确处理所有边界情况
✅ 保留数据中的有效零值
✅ 只移除末尾的填充零
✅ 处理各种数值范围
✅ 行为稳定且可预测
这个实现现在可以安全地用在您的 SM4 加密解密过程中了!
⭐ 优秀实践分享:SM4 加解密核心代码
🔐 核心函数实现
加密与解密核心逻辑
def encrypt_sm4_hex(key: str, value: str) -> str:"""SM4 HEX模式加密"""crypt_sm4 = CryptSM4(mode=SM4_ENCRYPT, padding_mode=1)crypt_sm4.set_key(bytes.fromhex(key), SM4_ENCRYPT)encrypted_value = crypt_sm4.crypt_ecb(bytes.fromhex(value))return encrypted_value.hex().upper()def decrypt_sm4_hex(key: str, encrypted_value: str) -> str:"""SM4 HEX模式解密"""crypt_sm4 = CryptSM4(mode=SM4_DECRYPT, padding_mode=1)crypt_sm4.set_key(bytes.fromhex(key), SM4_DECRYPT)decrypted_value = crypt_sm4.crypt_ecb(bytes.fromhex(encrypted_value))return decrypted_value.hex().upper()
📋 实用测试用例
def test_sm4_encryption():key = 'B94D4DC157B96C52994D4DC157B96C52'data = '28EE57035300CD6594C868EA0DBE8E75'# 测试加密encrypted = encrypt_sm4_hex(key, data)print(f"Encrypted: {encrypted}")# 测试解密decrypted = decrypt_sm4_hex(key, encrypted)print(f"Decrypted: {decrypted}")# 验证加解密是否一致assert data == decrypted, "加解密结果不一致!"print("SM4加解密测试通过!")
⚙️ 实际运行输出
Encrypted: 7B88F55214451C45E9C80B62F354ADDF
Decrypted: 28EE57035300CD6594C868EA0DBE8E75
SM4加解密测试通过!
⭐ 关键实践与总结
📌 优化代码的实用技巧
1.函数多实现
- 针对功能性函数,提供不同风格的实现(如普通函数、列表推导式、lambda表达式)。
2. 边界处理: - 针对空数据、全零数据等特殊场景,确保逻辑鲁棒性。
3. 统一日志格式: - 记录详细的输入输出,特别是加解密的中间值。
logger.info(f"Input Key: {key}")
logger.info(f"Input Data: {value}")
logger.info(f"Encrypted Value: {encrypted}")
📌 最佳实践分享
1. 日志驱动调试:
- 在调试过程中记录关键输入、输出和状态变化,有助于快速定位问题。
2. 单元测试覆盖率: - 设计测试用例时覆盖正常、异常和边界场景。
3. 选择主流填充模式: - 如非特殊需求,优先使用 PKCS7 填充。
📝 总结与启发
通过这次 gmssl 填充问题的修复,我深刻体会到:
1. 开源库需谨慎使用: 尤其是小众库,可能存在实现细节问题。
2. 代码设计需注重鲁棒性:边界检查、输入输出验证是关键。
3. 问题解决后需复盘总结:将经验分享出来,不仅能帮助他人,也能提升自己。
希望这篇文章能为你的项目开发提供参考。如果你有类似的经历,欢迎留言交流!让我们在技术道路上共同进步!😊
🔗 互动话题
- 你在使用加密库时踩过哪些坑?如何解决的?
- 你对 SM4 或 gmssl 库有其他疑问或经验吗?
期待你的分享! 🎉
相关文章:
️️️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践20241212
🛡️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践 ✨ 引言 在当下的数据安全环境中,SM4作为中国国家密码算法的代表性选择,被广泛应用于金融、通信和政府领域。然而,在实际开发中,即便是开…...
深度学习实验十四 循环神经网络(1)——测试简单循环网络的记忆能力和梯度爆炸实验
目录 一、数据集构建 1.1数据集的构建函数 1.2加载数据集并划分 1.3 构建Dataset类 二、模型构建 2.1嵌入层 2.2SRN层 2.3模型汇总 三、模型训练 3.1 训练指定长度的数字预测模型 3.2 损失曲线展示 四、模型评价 五、修改 附完整可运行代码 实验大体步骤&#x…...
AWS re:Invent 发布新的数据库产品 Aurora DSQL; NineData SQL编程大赛开始; 腾讯云支持PostgreSQL 17
重要更新 1. AWS re:Invent 发布新的数据库产品 Aurora DSQL ,提供了跨区域、强一致、多区域读写的能力,同时具备99.999%(多区域部署)的可用性,兼容PostgreSQL;同时发布的还有 DynamoDB 也提供类似的跨区域…...
STM32 OLED屏幕驱动详解
一、介绍 OLED是有机发光二极管,又称为有机电激光显示(Organic Electroluminescence Display, OLED)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广…...
Python字符串常用操作
Python字符串常用操作 一、字符串的切片 1.1、通过下标及下标范围取值 my_str myNameIsTaichi value1 my_str[2] # 正向 N value2 my_str[-5] # 反向 从 -1 开始 a字符串分割,语法:string[end: step] start:头下标,以0开…...
Redis 生产问题(重要)
缓存穿透 什么是缓存穿透? 缓存穿透说简单点就是大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。这就导致这些请求直接到了数据库上,根本没有经过缓存这一层,对数据库造成了巨大的压力…...
前端 —— Git
Git安装 下载安装包 【免费】前端前置-Git安装包资源-CSDN文库 安装 ‘git‘不是内部或外部命令及Git 的保姆级安装教程(保姆级教程)_git不是内部或外部命令-CSDN博客 vscode添加gitbash终端 setting.json "terminal.integrated.profiles.win…...
【GL006】Linux 之 shell
目录 一、shell 指令 1.1 体验shell指令 1.2 命令格式 1.3 shell中的通配符 1.4 输入输出重定向 1.5 命令置换 1.6 基本系统维护命令 1.7 Linux的进程管理命令 1.8 文件系统相关命令 1.9 Linux网络配置管理 二、shell 编程 2.1 shell 脚本的基础知识 2.2 shell 变…...
JS听到了强运的回响
正则表达式 介绍 正则表达式是用于匹配字符串中字符组合的模式,在JS中,正则表达式也是对象 通常用来查找,替换那些符合正则表达式的文本 就是筛选出符合条件的一类人 比如说 有人喜欢玩艾斯爱慕,那他喜欢的就是这一类人&…...
Linux下MySQL的简单使用
Linux下MySQL的简单使用 导语MySQL安装与配置 MySQL安装密码设置 MySQL管理 命令 myisamchkmysql其他 常见操作 C语言访问MYSQL 连接例程错误处理使用SQL 总结参考文献 导语 这一章是MySQL的使用,一些常用的MySQL语句属于本科阶段内容,然后是C语言和M…...
.net core使用AutoMapper
AutoMapper 是一个用于 .NET 平台的对象映射工具,它简化了不同对象类型之间的转换过程。在软件开发中,尤其是在分层架构的应用程序里,常常需要在不同的对象模型之间进行数据传递,例如从数据库实体到视图模型、DTO(数据…...
nmap详解
Nmap(Network Mapper)是一个开放源代码的网络探测和安全审核的工具。由于它的功能强大,被广泛应用于网络安全领域。以下是Nmap的一些主要功能及其在实战中的应用举例。 Nmap的主要功能: 端口扫描:检测目标主机上开放…...
CentOS7环境安装php
直接安装 yum -y install php CentOS7默认安装是php5,现在php已有8.3版本 先查看php -v 版本 如果是低版本,可以删除 yum remove php yum remove php-fpm yum remove php-common 一、添加REMI存储库 yum install epel-release yum install -y …...
基于深度学习的猫狗识别系统【深度学习课设】
🏆 作者简介:席万里 ⚡ 个人网站:https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜,同时略懂Vue与React前端技术,也了解一点微信小程序开发。 🍻 对计算机充满兴趣,愿意并且希望学习更多的技…...
字体子集化实践探索
最近项目rust生成PDF组件printpdf需要内嵌完整字体导致生成的PDF很大,需要做压缩,但是rust的类库allsorts::subset::subset不支持windows,所以做了一些windows下字体子集化的尝试 方案一:node.js做子集化 fontmin 缺点是也需要集…...
A1017 基于Java+JSP+SQL Server+servlet的二手购物平台的设计与实现
二手购物平台 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 摘 要 计算机以及网络技术的飞速发展,网络的应用在全国乃至全球日益普及,随着人们的思想水平和生活水平的提高,网络已经是人们必不可少的一部分。人们的…...
Simdroid-EC:液冷仿真新星,助力新能源汽车电机控制器高效散热
近年来,新能源电动车的销量呈现出快速增长的态势。据统计,2024 年1-10月中国新能源汽车销量达728万辆,同比增长37.8%。 电机控制器在新能源汽车中对于保障动力和安全性能扮演着至关重要的角色,其核心部件IGBT(绝缘栅双…...
C语言——实现并求出两个数的最大公约数
问题描述:求出两个数的最大公约数 //求两个数的最大公约数 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<time.h>int main() {int a,b;printf("请您输入两个数 a 和 b\n");scanf…...
今天你学C++了吗?——C++中的类与对象(日期类的实现)——实践与知识的碰撞❤
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
享元模式的理解和实践
在软件开发中,性能优化是一个永恒的话题。在追求高性能的过程中,减少内存的使用是一项重要的任务。享元模式(Flyweight Pattern)就是一种用于减少内存使用量的设计模式,它特别适用于存在大量重复对象的场景。本文将详细…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
