️️️ 避坑指南:如何修复国密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 库有其他疑问或经验吗?

期待你的分享! 🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

沈阳理工大学《2024年811自动控制原理真题》 (完整版)

本文内容,全部选自自动化考研联盟的:《沈阳理工大学811自控考研资料》的真题篇。后续会持续更新更多学校,更多年份的真题,记得关注哦~ 目录 2024年真题 Part1:2024年完整版真题 2024年真题

2023 年 408 大题解析

讲解视频推荐: 【BOK408真题讲解-2023】 一、数据结构 1. 算法题(图的邻接矩阵)13’ 已知有向图 G 采用邻接矩阵存储,类型定义如下: typedef struct{ //图的类型定义int num Vertices, numEdges; //图的顶点数和有…

【R语言】基础知识

一、对象与变量 R语言中的所有事物都是对象,如向量、列表、函数,变量、甚至环境等。它的所有代码都是基于对象object的操作,变量只是调用对象的手段。 1、对象 在R语言中,对计算机内存的访问是通过对象实现的。 # 字符型向量 …

【SpringBug】lombok插件中@Data不能生成get和set方法

一:问题引入 可以看到我们在类UserInfo上写了Data注解,但是在测试文件中生成的反编译target文件Us二Info中没有get和set方法 二:解决方法 1:Spring升级问题(解决了我的问题) 原因是Spring官方进行了升级…

Java版-图论-最短路-Floyd算法

实现描述 网络延迟时间示例 根据上面提示,可以计算出,最大有100个点,最大耗时为100*wi,即最大的耗时为10000,任何耗时计算出来超过这个值可以理解为不可达了;从而得出实现代码里面的: int maxTime 10005…

STM32 CubeMx HAL库 独立看门狗IWDG配置使用

看门狗这里我就不多介绍了,能搜到这篇文章说明你了解 总之就是一个单片机重启程序,设定好超时时间,在超时时间内没有喂狗,单片机就会复位 主要应用在单片机异常重启方面,比如程序跑飞(注意程序跑飞时你就…

uni-app实现小程序、H5图片轮播预览、双指缩放、双击放大、单击还原、滑动切换功能

前言 这次的标题有点长,主要是想要表述的功能点有点多; 简单做一下需求描述 产品要求在商品详情页的头部轮播图部分,可以单击预览大图,同时在预览界面可以双指放大缩小图片并且可以移动查看图片,双击放大&#xff0…

3D 生成重建035-DiffRF直接生成nerf

3D 生成重建035-DiffRF直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 本文提出了一种基于渲染引导的三维辐射场扩散新方法DiffRF,用于高质量的三维辐射场合成。现有的方法通常难以生成具有细致纹理和几何细节的三维模型,并且容易出…

中国计算机学会计算机视觉专委会携手合合信息举办企业交流活动,为AI安全治理打开“新思路”

近期,《咬文嚼字》杂志发布了2024年度十大流行语,“智能向善”位列其中,过去一年时间里,深度伪造、AI诈骗等话题屡次登上热搜,AI技术“野蛮生长”引发公众担忧。今年9月,全国网络安全标准化技术委员会发布了…

详解多租户架构下的资源隔离模式

文章目录 0.简介1.多租户概念1.1 基本概念1.2 单租户 vs 多租户 2.实现方案2.1 独立数据库方案2.1.1 优点2.1.2 缺点2.1.3 应用场景 2.2 共享数据库,独立 Schema2.2.1 优点2.2.2 缺点2.2.3 应用场景 2.3 共享数据库、共享Schema、共享表2.3.1 优点2.3.2 缺点2.3.3 应…

SMMU软件指南SMMU编程之寄存器

安全之安全(security)博客目录导读 本博客介绍了SMMUv3的编程接口: • SMMU寄存器 • 流表(Stream table) • CD(Context Descriptor) • 事件队列(Event queue) • 命令队列(…

分布式 窗口算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & 窗口算法 & 总结》《分布式 & 窗口算法 & 问题》 参考文献 《【算法】令牌桶算法》 固定窗口算法 简介 固定窗口算法是最简单的流量控制算法。固定窗口算法的核心原理是将系统的生命周期划分为一个个…

SEC_ASA 第二天作业

拓扑 按照拓扑图配置 NTP,Server端为 Outside路由器,Client端为 ASA,两个设备的 NTP传输使用MD5做校验。(安全 V4 LAB考点) 提示:Outside路由器作为 Server端要配置好正确的时间和时区,ASA防…

【电力负荷预测实例】采用新英格兰2024年最新电力负荷数据的XGBoost电力负荷预测模型

与小编上篇文章介绍的基于BPNN神经网络的电力负荷预测相比较,两种模型的负荷预测方法各有优势,神经网络能够自动提取特征并处理非线性关系,而XGBoost则具有预测精度高、运行速率快和可解释性强的特点。在实际应用中,可以根据具体需…

数据库数据恢复—ORACLE常见故障有哪些?如何恢复数据?

Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。 Oracle数据库数据恢复方案: 1、检测存放数据库的服务器/存储设备是否存…

ArcGIS MultiPatch数据转换Obj数据

文章目录 ArcGIS MultiPatch数据转换Obj数据1 效果2 技术路线2.1 Multipatch To Collada2.2 Collada To Obj3 代码实现4 附录4.1 环境4.2 一些坑ArcGIS MultiPatch数据转换Obj数据 1 效果 2 技术路线 MultiPatch --MultipatchToCollada–> Collada --Assimp–> Obj 2.…

简单vue3前端打包部署到服务器,动态配置http请求头后端ip方法教程

vue3若依框架前端打包部署到服务器,需要部署到多个服务器上,每次打包会很麻烦,今天教大家一个动态配置请求头api的方法,部署后能动态获取(修改)对应服务器的请求ip 介绍两种方法,如有需要可以直接尝试步骤一&#xff…

vue3-count-to实现数字动态增长效果

vue3-count-to 是一个用于 Vue 3的数字计数动画库,常用于在页面上实现数字的动态增长效果,类似于从某个起始值渐变到目标值的效果。它可以用来显示各种数字、统计数据或展示动画效果。 1 安装 vue3-count-to 首先,你需要安装 vue3-count-to …

android AIDL ipc binder转换

一. 概述 众所周知AIDL并不是所有的数据类型都可以传输。 可以传输的类型包括: 1.原生类型 2.String 3. CharSequence 4. List 5.Map 6. Binder 7. Parcelable 容器类 parcelable传输的时候会分解成成员,数组item的方式,传输完成后再进行…

CityEngine实践——常用cga文件解析系列(2)

上回书说到了: 3、RULES/COMPONENTS/MASSING/SUBURBAN_BLOCK DETACHED_HOUSES.CGA ROWHOUSES.CGA SEMI_DETACHED_HOUSES.CGA 4、RULES/COMPONENTS/MASSING/URBAN_BLOCK MONOBLOCK.CGA PERIMETER_8_SHAPE.CGA PERIMETER_MULTIPART.CGA 这个cga挺有意思&#xff0c…