️️️ 避坑指南:如何修复国密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)就是一种用于减少内存使用量的设计模式,它特别适用于存在大量重复对象的场景。本文将详细…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
2025.6.9总结(利与弊)
凡事都有两面性。在大厂上班也不例外。今天找开发定位问题,从一个接口人不断溯源到另一个 接口人。有时候,不知道是谁的责任填。将工作内容分的很细,每个人负责其中的一小块。我清楚的意识到,自己就是个可以随时替换的螺丝钉&…...

aurora与pcie的数据高速传输
设备:zynq7100; 开发环境:window; vivado版本:2021.1; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程,pc通过pcie传输给fpga,fpga再通过aur…...