Python 实现高效的 SM4 大文件加密解密实战指南20241024
Python 实现高效的 SM4 大文件加密解密实战指南
引言
在数据安全领域,使用对称加密算法如SM4进行数据保护非常常见。特别是当处理大文件时,合理的内存和块大小管理以及加密解密效率变得尤为重要。本文将分享如何使用Python进行大文件的SM4加密解密操作,并对代码进行优化,加入异常处理和内存管理措施,确保程序在处理大文件时的稳定性。
目录
- 背景介绍
- SM4算法概述
- 挑战与解决方案
- 填充处理的重要性
- 大文件的分块处理
- 完整代码实现
- 环境准备
- AlgorithmTool 类的实现
- SM4FileHelper 类的实现(含详细注释)
- 代码解析与说明
- 填充与去填充
- 按块加密解密逻辑
- 处理最后一个数据块
- 最佳实践与注意事项
- 内存优化
- 异常处理
- 安全性考虑
- 总结
背景介绍
SM4 是我国国家密码管理局制定的对称加密算法,被广泛应用于数据保护领域。然而,在对大文件进行加密解密时,如果不合理管理内存和块的大小,程序可能会崩溃或变得非常缓慢。我们将通过优化代码和加入合适的异常处理机制,提升程序的鲁棒性和性能。
SM4 算法概述
SM4 是一种分组对称加密算法,其块大小和密钥长度均为128位(16字节)。它的安全性和高效性使其成为移动通信、电子政务等领域的首选算法。
挑战与解决方案
初始问题
在使用SM4进行大文件加密解密时,您可能遇到以下问题:
- 加密后的文件大小与原始文件大小相同:加密后的文件应该比原文件略大,这是由于填充机制导致的。
- 解密后的文件内容不正确,无法还原到原始文件。
问题分析
通过代码分析,我们发现了以下问题:
- 填充处理不当:加密过程中,最后一个数据块没有正确处理填充,导致加密数据的长度与原始数据不匹配。
- 数据块未对齐:SM4 的块大小是16字节,但在加密和解密时使用了不同的块大小,导致数据块未正确对齐。
解决方案
通过以下改进,我们修复了这些问题:
- 调整数据块的大小:使用16的倍数作为块大小(例如16 * 1024字节),确保数据块与SM4的块大小对齐。
- 正确处理填充:仅对最后一个数据块进行填充,解密时正确去除填充。
- 添加异常处理:引入合理的异常处理机制,确保在文件读取、加解密过程中处理意外情况。
完整代码实现(含详细注释)
环境准备
确保安装了gmssl
库:
pip install gmssl
AlgorithmTool 类的实现
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT# 工具类:提供SM4加解密以及填充处理
class AlgorithmTool:def __init__(self):pass# 将16进制字符串转换为字节数据@staticmethoddef hex_string_to_bytes(data):return bytes.fromhex(data.replace(" ", ""))# PKCS7填充算法,确保数据长度是16字节的整数倍def pkcs7_padding(self, data):pad_len = 16 - (len(data) % 16) # 计算需要填充的字节数padding = bytes([pad_len] * pad_len) # 生成填充字节return data + padding # 将填充字节附加到数据末尾# 去除PKCS7填充,恢复原始数据def pkcs7_unpadding(self, data):pad_len = data[-1] # 读取最后一个字节,获取填充长度return data[:-pad_len] # 移除填充字节# 使用SM4进行ECB模式加密def encrypt_sm4(self, key, value):crypt_sm4 = CryptSM4()crypt_sm4.set_key(self.hex_string_to_bytes(key), SM4_ENCRYPT) # 设置加密密钥return crypt_sm4.crypt_ecb(value) # 返回加密后的字节数据# 使用SM4进行ECB模式解密def decrypt_sm4(self, key, encrypted_value):crypt_sm4 = CryptSM4()crypt_sm4.set_key(self.hex_string_to_bytes(key), SM4_DECRYPT) # 设置解密密钥decrypted_data = crypt_sm4.crypt_ecb(encrypted_value) # 进行解密return self.pkcs7_unpadding(decrypted_data) # 去除填充,返回解密后的数据
SM4FileHelper 类的实现(含详细注释)
import os
import io# 文件加密辅助类:提供按块加密和解密大文件的功能
class SM4FileHelper:def __init__(self, key):self.ag_tool = AlgorithmTool() # 使用AlgorithmTool处理加解密self.key = key # 16进制密钥self.block_size = 16 * 1024 # 块大小为16的倍数# 加密文件,并在文件开头保存原始文件大小信息def encrypt_file(self, input_file_path, output_file_path):"""按块加密文件内容,并在文件开头存储原始文件大小"""try:# 获取输入文件的总大小file_size = os.path.getsize(input_file_path)# 打开输入和输出文件with open(input_file_path, 'rb') as f_in, open(output_file_path, 'wb') as f_out:# 写入文件大小,便于解密时恢复f_out.write(file_size.to_bytes(8, byteorder='big'))# 循环按块读取文件while True:chunk = f_in.read(self.block_size) # 读取数据块if not chunk:break # 如果没有数据,则结束循环if len(chunk) < self.block_size:# 如果是最后一个块,进行填充后加密padded_chunk = self.ag_tool.pkcs7_padding(chunk)encrypted_chunk = self.ag_tool.encrypt_sm4(self.key, padded_chunk)else:# 如果是完整的块,直接加密encrypted_chunk = self.ag_tool.encrypt_sm4(self.key, chunk)f_out.write(encrypted_chunk) # 写入加密后的数据except IOError as e:print(f"文件操作错误: {e}") # 处理文件读写错误except Exception as e:print(f"加密过程中的错误: {e}") # 处理加密过程中的其他异常# 解密文件,并恢复原始文件内容def decrypt_file(self, input_file_path, output_file_path):"""按块解密文件内容"""try:# 打开输入和输出文件with open(input_file_path, 'rb') as f_in_raw, open(output_file_path, 'wb') as f_out:f_in = io.BufferedReader(f_in_raw)# 读取文件开头的原始文件大小original_file_size = int.from_bytes(f_in.read(8), byteorder='big')decrypted_size = 0 # 已解密的数据大小# 循环按块解密文件while True:encrypted_chunk = f_in.read(self.block_size + 16) # 读取加密数据块if not encrypted_chunk:break # 如果没有数据,则结束循环if f_in.peek(1) == b'': # 判断是否为最后一个块# 最后一个块,进行解密后去填充,并调整大小decrypted_chunk = self.ag_tool.decrypt_sm4(self.key, encrypted_chunk)remaining_size = original_file_size - decrypted_size # 计算剩余未写入的大小decrypted_chunk = decrypted_chunk[:remaining_size] # 截断填充后的多余数据else:# 非最后一个块,直接解密decrypted_chunk = self.ag_tool.decrypt_sm4(self.key, encrypted_chunk)f_out.write(decrypted_chunk) # 写入解密后的数据decrypted_size += len(decrypted_chunk) # 更新已解密数据的大小except IOError as e:print(f"文件操作错误: {e}") # 处理文件读写错误except Exception as e:print(f"解密过程中的错误: {e}") # 处理解密过程中的其他异常# 比较两个文件的大小,用于验证解密文件与原文件是否一致def compare_file_size(self, original_file_path, decrypted_file_path):"""比较两个文件的大小"""try:# 获取原文件和解密后文件的大小original_size = os.path.getsize(original_file_path)decrypted_size = os.path.getsize(decrypted_file_path)# 输出文件大小对比结果print(f"原文件大小: {original_size} 字节")print(f"解密文件大小: {decrypted_size} 字节")# 检查文件大小是否一致if original_size == decrypted_size:print("文件大小一致。")else:print("文件大小不一致!")except IOError as e:print(f"比较文件大小时的错误: {e}") # 处理文件操作异常
测试代码
if __name__ == '__main__':key = '5A3F323272CEA0640C711129E0B6043B' # 您的16进制密钥sm4_helper = SM4FileHelper(key)input_file = 'testbig.jpg' # 要加密的文件encrypted_file = 'encrypted_testbig.sm4' # 保存加密文件decrypted_file = 'decrypted_testbig.png' # 解密后的文件# 加密文件sm4_helper.encrypt_file(input_file, encrypted_file)print(f"文件 {input_file} 已加密保存到 {encrypted_file}")# 解密文件sm4_helper.decrypt_file(encrypted_file, decrypted_file)print(f"文件 {encrypted_file} 已解密保存到 {decrypted_file}")# 比较文件大小sm4_helper.compare_file_size(input_file, decrypted_file)
代码解析与说明
填充与去填充
- PKCS7填充:在
AlgorithmTool
类中实现,用于确保数据长度是块大小的整数倍。 - 填充过程:
- 计算填充字节数
pad_len = 16 - (len(data) % 16)
。 - 生成填充字节
padding = bytes([pad_len] * pad_len)
。 - 将填充字节附加到原数据末尾。
- 计算填充字节数
- 去填充过程:
- 读取最后一个字节,获取填充长度
pad_len = data[-1]
。 - 移除填充字节
data[:-pad_len]
。
- 读取最后一个字节,获取填充长度
按块加密解密逻辑
- 块大小选择:
16 * 1024
字节,满足SM4的块大小为16的倍数,同时平衡处理效率和内存占用。 - 加密逻辑:
- 按块读取文件,检查是否是最后一个块:
- 最后一个块进行填充后加密。
- 非最后一个块直接加密。
- 写入加密后的数据到输出文件。
- 按块读取文件,检查是否是最后一个块:
- 解密逻辑:
- 按块读取加密文件,检查是否是最后一个块:
- 最后一个块解密后去除填充,并根据原始文件大小截断多余字节。
- 非最后一个块直接解密。
- 按块读取加密文件,检查是否是最后一个块:
处理最后一个数据块
- 加密时的填充:
- 只有最后一个数据块需要填充,确保数据长度为16字节的倍数。
- 解密时的去填充:
- 仅对最后一个数据块进行去填充处理,并截断多余字节,确保解密文件与原文件一致。
最佳实践与注意事项
内存优化
- 按块处理:通过分块读取,避免内存占用过高。
- 块大小调整:根据具体情况灵活调整
block_size
。
异常处理
- 文件操作异常:添加
try-except
块,处理文件读写错误。 - 加解密异常:捕获加解密过程中可能的错误,如密钥错误或数据格式问题。
安全性考虑
- 密钥管理:妥善存储和传输加密密钥,避免密钥泄露。
- 敏感信息保护:不要在日志中记录密钥或未加密数据。
总结
通过这次实践,成功解决了SM4加密和解密过程中遇到的问题,深入理解了对称加密算法的细节。正确处理数据块的填充和按块读取处理确保了内存占用的优化和加解密结果的准确性。
相关文章:
Python 实现高效的 SM4 大文件加密解密实战指南20241024
Python 实现高效的 SM4 大文件加密解密实战指南 引言 在数据安全领域,使用对称加密算法如SM4进行数据保护非常常见。特别是当处理大文件时,合理的内存和块大小管理以及加密解密效率变得尤为重要。本文将分享如何使用Python进行大文件的SM4加密解密操作&…...
数据结构~红黑树
文章目录 一、红黑树的概念二、红黑树的定义三、红黑树的插入四、红黑树的平衡五、红黑树的验证六、红黑树的删除七、完整代码八、总结 一、红黑树的概念 红黑树是一棵二叉搜索树,他的每个结点增加⼀个存储位来表示结点的颜色,可以是红色或者黑色。通过…...
【ROS GitHub使用】
提示:环境配置为Ubuntu20.04&ROS Noetic 文章目录 前言一、创建工作空间目录二、尝试从GitHub上下载一个源码包,对它进行编译,运行这个源码包1.打开script文件夹,右键文件夹空白区域,选择在中端中打开;…...
批量处理文件权限:解决‘/usr/bin/chmod: Argument list too long’的有效方法
批量处理文件权限:解决‘/usr/bin/chmod: Argument list too long’的有效方法 错误原因解决方案1. 分批处理2. 使用xargs3. 增加ARG_MAX限制4. 使用脚本 结论 在Linux系统中,有时你可能会遇到这样的错误消息:“/usr/bin/chmod: Argument lis…...
数据结构——树——二叉树——大小堆
目录 1>>导言 2>>树 2.1>>树的相关术语 2.2>>树的表示和应用场景 3>>二叉树 3.1>>完全二叉树 3.2>>大小根堆 4>>结语 1>>导言 上篇小编将队列的内容给大家讲完了,这篇要步入新的篇章,请宝…...
Android Junit 单元测试 | 依赖配置和编译报错解决
问题 为什么在依赖中添加了testImplement在build APK的时候还是会报错?是因为没有识别到test文件夹是test源代码路径吗? 最常见的配置有: implementation - 所有源代码集(包括test源代码集)中都有该依赖库.testImplementation - 依赖关系仅在test源代码…...
ffmpeg视频滤镜: 裁剪-crop
滤镜简述 crop官网链接 > FFmpeg Filters Documentation crop滤镜可以对视频进行裁剪,并且这个滤镜可以接受一些变量比如时间和帧数,这样我们实现动态裁剪,从而实现一些特效。 滤镜使用 参数 out_w <string> ..…...
身份证归属地查询接口-在线身份证归属地查询-身份证归属地查询API
接口简介:输入身份证号码可查询到所属地区、出生年日月以及性别。 接口地址:https://www.wapi.cn/api_detail/60/167.html 在线核验:https://www.wapi.cn/icard.html 网站地址:https://www.wapi.cn 返回格式:json,xml,…...
ESP32 S3 怎么开发基于ESP-RTC的音视频实时交互的应用,用语AI陪伴的领域
在ESP32-S3平台上开发基于ESP-RTC的音视频实时交互应用,尤其是在AI陪伴领域,涉及到音视频数据的采集、编码、传输和解码。ESP32-S3 具备较强的处理能力,且拥有丰富的接口和模块支持,可以用来实现这种功能。以下是一个完整的开发方…...
车载测试分享:UDS诊断、ECU刷写、CAN一致性测试、网络通讯测试、CANoe使用、报文解析、问题定位分析
FOTA模块中OTA的知识点:1.测试过程中发现哪几类问题? 可能就是一个单键的ecu,比如升了一个门的ecu,他的升了之后就关不上,还有就是升级组合ecu的时候,c屏上不显示进度条。 2.在做ota测试的过程中…...
预算不够,怎么跟KOL砍价?(内附砍价模板)
在当今的数字营销时代,海外红人(KOL)的影响力不容小觑。他们的一篇帖子、一个视频,甚至是一张照片,都有可能为企业带来巨大的流量和销量。 当企业满怀希望地找到一位粉丝众多、影响力强的KOL,准备洽谈合作…...
C#从零开始学习(GameObject实例)(unity Lab3)
这是书本中第三个unity Lab 在这次实验中,将学习如何使用C#编写代码用unity编写C#代码 GameObject实例 本次将完成的工作 将游戏资产配置在文件夹中创建材质把GameObject变成预制件脚本控制游戏防止球体重叠 将游戏资产配置在文件夹中 Script放代码 Prefabs放预制件 MAteria…...
谷歌地图 | 与 Android 版导航 SDK 集成的最佳实践
谷歌最近宣布了导航 SDK,它可以让您将熟悉的 Google 地图逐向导航体验无缝集成到您的 Android 和 iOS 应用程序中。 这篇博文概述了一些最佳实践,您可以使用这些实践为您的 Android 应用程序使用导航 SDK 构建流畅、一致且可靠的导航体验。 与导航地图…...
什么是 VolTE 中的 Slient Redial?它和 CSFB 什么关系?
目录 1. 什么是 Silent Redial(安静的重拨号)? 2. Silent Redial 信令流程概述 3. 总结 Silent Redial 和 CSFB 啥关系? 博主wx:yuanlai45_csdn 博主qq:2777137742 想要 深入学习 5GC IMS 等通信知识(加入 51学通信),或者想要 cpp 方向修改简历,模拟面试,学习指导都…...
docker 部署单节点的etcd以及 常用使用命令
docker部署etcd $ docker run -d --name etcd-server -p 2379:2379 -p 2380:2380 quay.io/coreos/etcd:v3.5.0 /usr/local/bin/etcd -name my-etcd-1 -advertise-client-urls http://0.0.0.0:2379 -listen-client-urls http://0.0.0.0:2379 -initial-advertise-peer-urls http…...
华为开放式耳机测评,南卡 、华为、Cleer开放式耳机超深度横评
近年来,开放式蓝牙耳机因其独特的设计和优势受到了越来越多消费者的青睐。其实对于开放式耳机,大家都没有一个明确的概念,可能会为了音质的一小点提升而耗费大量的资金,毕竟这是一个无底洞。 作为在过去一年体验过不下20款开放式耳…...
【Power Query】List.Select 筛选列表
List.Select 筛选列表 ——在列表中返回满足条件的元素 List.Select(列表,判断条件) 不是列表的可以转成列表再筛选,例如 Record.ToList 不同场景的判断条件参考写法 (1)单条件筛选 列表中小于50的数字 List.Select({1,99,8,98,5},each _<50) (2)多条件筛…...
Spring--4
SpringWeb 概念 是Spring框架的一个模块,基于Servlet的一个原始Web框架。 SpringWEB 运行流程 描述:前端用户请求发送的后端以后,先经过前端控制器DispatcherServlet(再次之前也可能有过滤器的存在),经过前端控制器解析后&…...
django celery 定时任务 Crontab 计划格式
Celery 定时任务教程 Celery 是一个强大的异步任务队列/作业队列基于分布式消息传递的开源项目。它广泛用于处理各种类型的后台任务,例如发送电子邮件、处理图像、数据分析和视频转换等。 本文将介绍如何使用 Celery 实现定时任务,包括: 安…...
动态应用程序安全测试 (DAST) 工具 Fortify WebInspect
Fortify WebInspect 是一种动态应用程序安全测试 (DAST) 工具,可识别所部署的Web 应用程序和服务中的应用程序漏洞。 OpenText™ 推出的 Fortify WebInspect 是一种自动化DAST 解决方案,可提供全面的漏洞检测能力并有助于安全专业人士和 QA 测试人员识别安全漏洞和…...
深入解析东芝TB62261FTG,步进电机驱动方案
TB62261FTG是一款由东芝推出的两相双极步进电机驱动器,采用了BiCD工艺,能够提供高效的电机控制。这款芯片具有多种优秀的功能,包括PWM斩波、内置电流调节、低导通电阻的MOSFET以及多种步进操作模式,使其非常适合用于需要精确运动控…...
Vue 常用的狗钩子函数
beforeCreate(){ console.log(刚刚创建实例); },created(){console.log(实例创建完成);},beforeMount(){console.log(模板编译之前 ); },mounted(){/* 请求数据,操作Dom时常用 */console.log(实力挂载完成);},beforeUpdate(){console.log(更新前)},update…...
【机器学习基础】激活函数
激活函数 1. Sigmoid函数2. Tanh(双曲正切)函数3. ReLU函数4. Leaky ReLU函数 1. Sigmoid函数 观察导数图像在我们深度学习里面,导数是为了求参数W和B,W和B是在我们模型model确定之后,找出一组最优的W和B,使…...
nnMamba用于糖尿病视网膜病变检测测试
1.代码修改 源码是针对3D单通道图像的,只需要简单改写为2D就行,修改nnMamba4cls.py代码如下: # -*- coding: utf-8 -*- # 作者: Mr Cun # 文件名: nnMamba4cls.py # 创建时间: 2024-10-25 # 文件描述:修改nnmamba,使…...
【Spring MVC】创建项目和建立请求连接
我的主页:2的n次方_ 1. MVC MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分。 View (视图): 指在应⽤程序中专⻔⽤来与浏览器进⾏交互&…...
台达A2伺服
驱动器: L 外接脉冲 U 在L的基础上增加DI E ethercat总线 F 台达 M CANopen总线 电机: ECMA-C A 0604 SS...
ReactOS系统中搜索给定长度的空间地址区间中的二叉树
搜索给定长度的空间地址区间 //搜索给定长度的空间地址区间 MmFindGap MmFindGapTopDown PVOID NTAPI MmFindGap(PMADDRESS_SPACE AddressSpace,ULONG_PTR Length,ULONG_PTR Granularity,BOOLEAN TopDown );PMADDRESS_SPACE AddressSpace,//该进程用户空间 ULONG_PTR Length,…...
Postgresql中和时间相关的字段类型及其适用场景
PostgreSQL 提供了多种数据类型来表示时间和日期,适用于不同的场景和需求。以下是常用的时间类型及其适用场景: 1. TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) 用途: 表示一个包含时区信息的日期和时间。 使用场景: 适合存储需要考虑时区变化的全球化应用…...
储能蓝海:技术革新与成本骤降引爆市场
在当今全球能源转型的大背景下,储能项目的前景无疑呈现出前所未有的乐观态势。其快速增长的装机规模、持续的技术创新与成本降低、政策的强力支持以及市场的迫切需求,共同绘制了一幅充满机遇与挑战的壮丽画卷。 快速增长的装机规模:储能市场的…...
java抽象类和接口
前言: 在 Java 编程中,抽象类和接口是面向对象编程(OOP)中的重要概念。它们都是用来定义抽象类型的机制,来帮助程序员构建更加灵活、可维护和可扩展的软件系统。 但是随着软件系统规模的不断扩大和复杂度的增加&…...
=> wordpress 翻译 不显示/网络培训课程
仅作为记录,大佬请跳过。 原因是命名重复 展示: 参考: 感谢大佬博主文章传送门...
毕业室内设计代做网站/必应站长平台
2021河源教师招聘备考交流群全省教招考情在线咨询2021紫金春招编制教师招聘33人考试笔试成绩公布,考生可登陆成绩查询网站:http://zk.sun-hrm.com/index.php/exam/?EXAMID1572 进行查询。面试根据笔试成绩从高分到低分按1:3的比例确定面试人选ÿ…...
大型科技网站/网站推广线上推广
Java认证备考:谁将成为Java世界杯的巴西队?谁将是Java世界杯的巴西队?既不是Sun也不是甲骨文,而是SpringSource,这个开源公司的CEO罗德约翰森(Rod Johnson)如是说。来自市场分析机构的一份调查结果,以及与谷歌共同参与制定的Jav…...
网站建设开发团队介绍/网络营销研究背景及意义
author:skate time:2008/2/18 oracle如何得到32位的世界唯一随机数 我们在创建表的时候一般都用序列生成的数字来保证数据的唯一,但这只能保证在单个实例中,无法适合并行或远程的环境的主关键字 因为在各自环境理里可能生成的数字重复,从而会…...
担路网口碑做网站好吗/如何引流被动加好友微信
9991阴魂不散!多多QQ表情病毒奥秘(转)QQ表情本来是广受用户欢迎的一个实用工具,然而,最近有人却利用人们对QQ表情的喜爱,将其变成了一种恶性病毒。最近,笔者不断接到求助电话,受到一款名叫多多QQ表情病毒的骚扰。笔者随…...
wordpress附件/站内优化主要从哪些方面进行
清除浮动之父级添加overflow 这样就能很好的解决这个问题了。 缺点:无法显示溢出的部分呀...