️️️ 避坑指南:如何修复国密gmssl 库填充问题并提炼优秀加密实践20241212

news2025/1/14 14:00:20

🛡️ 避坑指南:如何修复国密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 data
    
    Args:
        data: List of bytes with ZERO padding
        
    Returns:
        List of bytes with padding removed
        
    Examples:
        [1,2,3,0,0,0] -> [1,2,3]
        [1,2,0,3,0,0] -> [1,2,0,3]
    """
    if not data:
        return data
        
    for 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 passed

Input:    [1, 2, 3]
Expected: [1, 2, 3]
Got:      [1, 2, 3]
✓ Test passed

Input:    [0, 0, 0]
Expected: []
Got:      []
✓ Test passed

Input:    []
Expected: []
Got:      []
✓ Test passed

Input:    [1, 2, 0, 3, 0, 0]
Expected: [1, 2, 0, 3]
Got:      [1, 2, 0, 3]
✓ Test passed

Input:    [0, 1, 2, 0, 0]
Expected: [0, 1, 2]
Got:      [0, 1, 2]
✓ Test passed

Input:    [1, 0, 2, 0, 0]
Expected: [1, 0, 2]
Got:      [1, 0, 2]
✓ Test passed

Input:    [255, 0, 0, 0]
Expected: [255]
Got:      [255]
✓ Test passed

All 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.coloradmin.cn/o/2258846.html

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

相关文章

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言 使用c开发webrtc在互联网上留下的资料甚少,经过我一段时间的探…

【工具】linux matlab 的使用

问题1 - 复制图表 在使用linux matlab画图后,无法保存figure。 例如在windows下 但是在linux下并没有这个“Copy Figure”的选项。 这是因为 “ The Copy Figure option is not available on Linux systems. Use the programmatic alternative.” 解决方案&…

系统思考—本质

“执行力不足,真的是问题的根本吗?” 最近我和不少企业创办人交流时,大家普遍提到“执行力”的问题,但我发现,背后其实隐藏着更深层次的原因。当我用系统思考的视角深入拆解时,执行力不足,未必…

模方如何置平处理模型表面?

(1) 点击“多边形绘制“后在编辑模型视图中通过绘制多边形对 OBJ 进行编辑,将立面进行置平处理 选择需要表面置平的范围 (2) 点击“置平“即可看到效果

AAAI 2025 camera ready提交注意事项

您必须在截止日期前填写、签署并返回 AAAI 版权表(除非 AAAI Press 指示使用 AAAI 分发许可证)。 您必须根据作者的格式说明阅读并格式化您的论文和 PDF。 您必须使用我们的电子提交表格准时提交您的电子文件和摘要。 您必须向 AAAI Press 支付任何所需的…

QT核心功能概览

QT的学习(一)如何查阅QT文档?(以QPushButton为例)_qt的组件在qt文档那里面看-CSDN博客 QPushButton Class | Qt Widgets 5.15.18 一、前言 QT虽说功能很庞大,但是常用的控件也不是很多,也就只…

opencv——图片矫正

图像矫正 图像矫正的原理是透视变换,下面来介绍一下透视变换的概念。 听名字有点熟,我们在图像旋转里接触过仿射变换,知道仿射变换是把一个二维坐标系转换到另一个二维坐标系的过程,转换过程坐标点的相对位置和属性不发生变换&a…

动态流程图制作方法

动态流程图制作方法 1.方法1 有各种 echars模板 可以自己改代码 https://www.isqqw.com/viewer?id42201echars 在线生成 https://codevtool.com/echarts2. 方法2电脑软件,画图的。 《亿图图示》

H.323音视频协议

概述 H.323是国际电信联盟(ITU)的一个标准协议栈,该协议栈是一个有机的整体,根据功能可以将其分为四类协议,也就是说该协议从系统的总体框架(H.323)、视频编解码(H.263)、…

java八股-索引下推(图解对比)

参考链接 https://xiaolincoding.com/mysql/base/how_select.html#%E6%89%A7%E8%A1%8C%E5%99%A8 https://javaguide.cn/database/mysql/mysql-index.html#%E7%B4%A2%E5%BC%95%E4%B8%8B%E6%8E%A8 如何理解索引下推这个概念,其实就是index把Server层的工作&#xff0…

在 Ubuntu 中 make 是否是系统自带的?怎么样查看Linux系统中是否有make?

make 命令 并不是所有 Ubuntu 系统都默认安装的,但它通常是开发工具链的一部分,许多开发者会在安装系统后配置它。make 是一个非常重要的构建工具,用于自动化编译和构建过程,特别是在编译软件或内核时。 make 的来源 make 是一个…

Android系统(android app和系统架构)

文章目录 AndroidAndroid Apps四大组件 Android系统Platform API之下:一个微笑内核adb(Android Debug Bridge) Android包管理机制Android的Intent机制参考 Android LinuxFrameworkJVM 在Linux/Java上做了个二次开发?并不完全是:Android定义…

opencv——识别图片颜色并绘制轮廓

图像边缘检测 本实验要用到Canny算法,Canny边缘检测方法常被誉为边缘检测的最优方法。 首先,Canny算法的输入端应为图像的二值化结果,接收到二值化图像后,需要按照如下步骤进行: 高斯滤波。计算图像的梯度和方向。非极…

【Java笔记】LinkedList 底层结构

一、LinkedList 的全面说明 LinkedList底层实现了双向链表和双端队列特点可以添加任意元素(元素可以重复),包括null线程不安全,没有实现同步 二、LinkedList 的底层操作机制 三、LinkedList的增删改查案例 public class LinkedListCRUD { public stati…

(笔记)解决select下拉框默认选中selected属性不起作用问题

在 vue3 中使用 HTML原生开发,想给 select 下拉框选中 selected 属性不起作用。这是因为 vue3中使用了 Composition API(组合式 api),而 Composition API 中的响应式数据是独立的,不会自动更新到 DOM 中。可以使用 v-m…

国科大智能设备安全-APK逆向分析实验

APK逆向分析实验 使用APK常用逆向分析工具,对提供的移动应用程序APK文件进行逆向分析,提交逆向后代码和分析报告。具体任务如下: 任务一:安装并熟悉Apktool、Jadx等APK常用逆向工具的使用方法,对提供的Facebook Updat…

黑皮书-计算机科学导论02

目录 第二部分:计算机硬件 第5章计算机组成 5.1中央处理单元 Ⅰ.算数逻辑单元 Ⅱ.控制单元 Ⅲ.寄存器 5.2主存储器 Ⅰ.随机存取存储器(RAM) Ⅱ.只读存储器(ROM) 高速缓冲存储器(Cache) 5.3输入/输出子系统 Ⅰ.非存储设备 Ⅱ.存储设备(辅助存…

解决Linux安装yum时出现apt-get install E: 无法定位软件包问题

ubuntu系统安装mysql之前安装yum,出现报错:E: 无法定位软件包问题 (1)找到源镜像,备份 cd /etc/apt/ // 切换到/etc/apt/ 目录下 sudo cp sources.list sources.list.old // 先把源文件…

[工具升级问题] 钉钉(linux版)升级带来的小麻烦

本文由Markdown语法编辑器编辑完成。 1. 背景: 今日钉钉又发布了新的升级版本。由于我工作时使用的是Ubuntu 20.04版本,收到的升级推送信息是,可以升级到最新的7.6.25-Release版本。根据钉钉官方给出的历次更新版说明,这个新的版本&#xf…

UnityShaderLab 实现黑白着色器效果

实现思路:取屏幕像素的RGB值,将三个通道的值相加,除以一个大于值使颜色值在0-1内,再乘上一个强度值调节黑白强度。 在URP中实现需要开启Opaque Texture ShaderGraph实现: ShaderLab实现: Shader "Bl…