赞
踩
因为工作需要,接触到了各种加密算法 ,在学习过程中,也对其原理产生了一些兴趣,于是有了这篇学习笔记,也方便自己以后查阅。若文中有任何不正确的地方,敬请指正。
总所周知,常见的对称加密算法大致有DES 3DES以及AES等,现在常用的是AES
对于对称加密算法 我们常常关注的是它的分组模式以及填充模式
先大概介绍一些常见的对称加密算法、分组模式和填充模式,最后上实操
本文提到了两种实现的方法
1、使用python中的pycryptodome库来进行实现,无脑操作,不需要懂太多原理,适合只想知道怎么用 ,不需要知道什么原理的看官
2、不借助任何 库,纯手工实现,这里就讲个大概吧(本来准备把完整代码 附上,但是太麻烦最终放弃了)
这里我就讲一下大概的概念,以及从安全的角度分析一下优缺点。
详细的怎么加密细节就不展开了,后面要是时间的话再写写
全称是Data Encryption Standard,它是在20世纪70年代初期IBM研发的
DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。
密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。
优点:
安全性(在设计时期):在其发布之初,DES 被认为是相当安全的加密算法。它使用56位密钥对数据进行加密,使得破解密文变得非常困难,因为即使在计算机技术发展迅速的情况下,穷举搜索所有密钥的可能性也是非常耗时的。
性能良好:DES 加密和解密的速度很快,这对于许多应用来说是一个重要的优点。
标准化:DES 是一个广为接受和使用的标准,因此在许多领域都得到了广泛的应用。
缺点:
密钥长度过短:DES 的密钥长度只有56位,这在当前计算机技术条件下已经不再安全,因为可以使用强大的计算资源通过穷举搜索或其他更高级的攻击技术来破解密文。密钥空间的大小决定了安全性,而DES 的密钥空间相对较小,因此易受到暴力破解攻击。
现代计算能力足以破解:随着计算技术的发展,如今的计算机能够更快速地破解 DES 加密,从而降低了其安全性。
不足以抵御巨大的穷举搜索攻击:随着时间的推移,现代密码学的发展使得更多更有效的攻击方法成为可能,DES 的密钥长度已经无法提供足够的保护,因此不足以抵御巨大的穷举搜索攻击。
看这个名字就不难猜到,这种加密方式就是进行3次DES加密,需要3个DES密钥。
优点:
安全性提高:通过对数据应用三次DES加密,3DES提供了比单次DES更高的安全性。即使DES算法本身存在漏洞,使用3DES可以更好地保护数据。
向后兼容性:3DES仍然可以与原始的DES兼容。这意味着可以逐步过渡到更安全的3DES而不会破坏现有系统的功能。
相对成本低廉:与许多其他更现代的加密算法相比,3DES的实现成本相对较低。这是因为它基于原始的DES算法,而且已经被广泛采用和实现。
稳定性:3DES已经存在了很长时间,并且经过了广泛的测试和使用,因此它被认为是一个稳定可靠的加密算法。
缺点:
性能较低:由于3DES需要进行三次加密操作,因此它比单次DES加密要慢得多。这对于需要高性能的应用可能是一个问题,尤其是在资源受限的环境下。
密钥管理复杂:由于3DES需要使用三个不同的密钥,因此密钥管理变得更加复杂。需要确保密钥的安全性,以及在系统中正确地管理和轮换密钥。
较短的密钥长度:虽然3DES使用了三次加密,但它仍然使用56位的DES密钥。这使得它在面对现代计算能力下的安全性挑战时变得更加脆弱。
AES全称 Advanced Encryption Standard 它是由美国国家标准与技术研究所(NIST)于2001年采纳,作为取代DES(数据加密标准)的标准加密算法。AES算法设计简洁、结构清晰,并且在安全性、效率和灵活性方面都表现出色。AES已经成为广泛使用的加密标准,而DES已经逐渐被淘汰。
详细的关于AES的解释在最后一章节的实操中会解释
密钥长度:
- AES:支持128位、192位和256位三种密钥长度,提供了更大的密钥空间,因此具有更高的安全性。
- DES:固定的56位密钥长度,相对较短,密钥空间较小,安全性相对较低。
轮数(Rounds):
- AES:加密和解密过程中会进行多轮操作(通常是10轮、12轮或14轮,取决于密钥长度),每轮都包含一系列复杂的置换和替代操作。
- DES:加密和解密过程中只有16轮,且每轮操作相对简单。
分组长度:
- AES:采用固定的128位分组长度进行加密和解密。
- DES:采用64位分组长度进行加密和解密。
加密算法的结构:
- AES:采用代换-置换网络(Substitution-Permutation Network,SPN)结构,包括轮密钥加(AddRoundKey)、字节代换(SubBytes)、行移位(ShiftRows)和列混淆(MixColumns)等操作。
- DES:采用费斯妥网络(Feistel Network)结构,每轮操作涉及数据的分割、子密钥的生成和轮函数的应用。
替代和置换操作:
- AES:采用字节代换和行移位等操作,通过在有限域上的线性和非线性变换实现。
- DES:采用S盒代替(Substitution Box)和位移置换(Permutation)操作,通过固定的置换表实现。
分组密码:对称加密算法DES 3DES AES都属于分组密码,它们只能加密固定长度的明文
分组模式常见的有以下:
ECB 模式是最简单的分组密码模式,将明文分成固定大小的数据块,然后对每个数据块使用相同的密钥进行独立加密
由于相同的明文块会被加密成相同的密文块,ECB 模式不具备抵抗重放攻击的能力,且不适用于加密大量重复的数据
CBC 模式使用前一个密文块与当前明文块进行异或运算,然后再使用密钥加密,以增加密文的随机性
CBC 模式需要一个初始化向量(IV)来保证第一个明文块的随机性,同时密文块的计算依赖于前一个密文块,使得每个密文块的值都依赖于前面的明文块
CFB 模式将前一个密文块作为密钥加密的结果,然后将加密结果与当前明文块进行异或运算,以产生当前密文块
CFB 模式允许使用不连续的位(比特)流进行加密,因此适用于流加密(Stream Cipher)的场景
OFB 模式将前一个密钥加密的结果作为密钥,然后使用该密钥加密一个伪随机位流,再将位流与当前明文块进行异或运算,得到当前密文块
OFB 模式不依赖于前一个密文块,因此可以并行地加密和解密数据
CTR 模式使用计数器值与密钥的加密结果作为加密密钥,然后将计数器值作为明文与密钥进行异或运算,得到密文。
CTR 模式允许并行地加密和解密数据,且不需要填充
常见的 对称加密的填充方式有以下几种,最常用的还是PKCS7 Padding & Zero Padding
数据长度L,对称算法的分块长度A,L%A=0 长度刚好是分块长度的整倍数的时候,就不需要进行填充,这种情况称之为no Padding
在 Zero Padding 中,所有需要填充的字节都被填充为零
最后一个数据块中,填充的字节以零字节填充,直到数据块的大小达到加密算法所要求的大小
这种填充方式适用于某些特殊情况,如数据本身不包含零字节,且填充后的数据块长度需与加密算法要求的长度相匹配
示例:
数据:0x11 0x22 0x33 0x44 0x55 分块长度为8
padding后的数据:
0x11 0x22 0x33 0x44 0x55 0x00 0x00 0x00 (填充3个0x00)
在 ANSI X.923 Padding 中,填充的字节的值为零,最后一个字节表示填充的字节数
这种填充方式在一些特定的通信协议和标准中使用,如 ISO/IEC 7816-4 中的智能卡应用
示例:
数据:0x11 0x22 0x33 0x44 0x55 分块长度为8
padding后的数据:
0x11 0x22 0x33 0x44 0x55 0x00 0x00 0x03 (填充2个0x00 最后一位为填充长度0X03)
在 ISO 7816-4 Padding 中,填充的字节的值为 0x80,然后填充零字节,直到数据块的大小达到加密算法所要求的大小
与 ANSI X.923 Padding 类似,最后一个字节的值表示填充的字节数
这种填充方式也常用于智能卡应用,如 EMV(Europay, Mastercard, Visa)标准中的数据格式
示例:
数据:0x11 0x22 0x33 0x44 0x55 分块长度为8
padding后的数据:
0x11 0x22 0x33 0x44 0x55 0x80 0x00 0x00 (第一位为填充长度0X80 填充2个0x00)
若数据长度L,对称算法的分块长度8,则需填充8-(L%8)个字节的8-(L%8)
这样说可能不直观,举个例子:
数据: 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb
此时 L=11 就需要填充8-(11%8)=8-3=5 5个字节的0x05
padding后的数据:
0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
0x99 0xaa 0xbb 0x05 0x05 0x05 0x05 0x05(填充5个0x05)
PKCS5 Padding是PKCS7的一个特例
PKCS7 Padding中,若数据长度L,对称算法的分块长度A,则需填充A-(L%A)个字节的A-(L%A)
A可以为任意值,PKCS5中为8
举个例子:
数据: 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb 0xcc 0xdd A=16
此时 L=13 就需要填充16-(13%16)=16-13=3 3个字节的0x03
padding后的数据:
0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb 0xcc 0xdd 0x03 0x03 0x03 (填充3个0x03)
pycrypto,pycryptodome是crypto第三方库,pycrypto已经停止更新三年了,所以不建议安装这个库;pycryptodome是pycrypto的延伸版本,用法和pycrypto 是一模一样的;所以只需要安装pycryptodome就可以了
官方文档:AES — PyCryptodome 3.210b0 文档
Step1:安装库
pip install pycryptodomex
Step2:直接开干,库的使用都很简单,就举一个例子吧 DES_PKCS7_ECB
代码如下:
#!/usr/bin/env python # -*- coding: UTF-8 -*- ''' @Project :test @File :test.py @IDE :PyCharm @Author :Lin @Date :2024/4/23 22:39 ''' #如果你要使用3DE 或者 AES 就再import DES3(对应3DES算法)和AES from Cryptodome.Cipher import DES from Cryptodome.Util.Padding import pad,unpad from Cryptodome.Random import get_random_bytes #明文数据 data=b'hello linver' print("data原始数据为:",data) #DES的密钥 可以自己定义 长度为8 key=b'12345678' #也可以随机生成 使用到Random模块中的函数 这里设置长度为8 因为DES的密钥长度固定为8字节 #如果是3DES的话,密钥长度默认为8字节,也可以为16字节,24字节 #AES的话,默认是16字节(128)也可以是24字节(192)24字节(256) key_random=get_random_bytes(8) #定义加密函数 DES3的话就换成DES3 AES就换成AES 所有都是 def encrypt_des_ecb_pkcs7(data,key): #创建DES的加密器对象 cipher=DES.new(key,DES.MODE_ECB) #对data进行填充 padded_data=pad(data,DES.block_size,style='pkcs7') #查看以下填充后的data print("填充后的数据为:",padded_data) #进行加密 cipher_data=cipher.encrypt(padded_data) #返回加密后的data return cipher_data #定义解密函数 def decrypt_des_ecb_pkcs7(cipher_data,key): #创建DES解密器对象 cipher=DES.new(key,DES.MODE_ECB) #解密 decrypted_data=cipher.decrypt(cipher_data) #去除填充 unpadded_data=unpad(decrypted_data,DES.block_size,style='pkcs7') #返回解密后的data return unpadded_data if __name__=="__main__": #这里使用自己定义的key 如果你想随机生成key 则使用key_random cipher_data=encrypt_des_ecb_pkcs7(data,key) print("加密后的data为:",cipher_data) print("------------") print("将加密后的数据使用相同的key进行解密") #判断解密后的数据 unpadded_data是否和原始data相同 unpadded_data = decrypt_des_ecb_pkcs7(cipher_data, key) if unpadded_data==data: print("解密后的data为:",unpadded_data)结果如下:
F:\script\test\venv\Scripts\python.exe F:\script\test\test.py data原始数据为: b'hello linver' 填充后的数据为: b'hello linver\x04\x04\x04\x04' 加密后的data为: b'\x14\xffjP\x19Q\xa2\x14\xf8\xb8\xd1\xe6\xd7E8\x82' ------------ 将加密后的数据使用相同的key进行解密 解密后的data为: b'hello linver' Process finished with exit code 0
Tips:
此处可以看出支持的分组方式有以下种类,需要哪种选哪种,
此处可以看出 可以选择填充的分块大小和填充方式,填充的分块大小选择DES.block_size
可以选择的填充方式为pkcs7、iso7816和x923这三种方式,如果你想用其他的填充方式,可以自己写填充函数来实现,后面会提及到。
实现步骤如下(AES128_PKCS7_ECB):
STEP 1:对明文进行分组
AES128分组长度为 128 比特每个明文块包含 16 个字节
如果明文长度不是 16 的整数倍,则需要进行填充操作,这里我们选择的是PKCS7 Padding
代码如下 :
#定义填充方式 这里使用PKCS7 Padding 分块长度为 16字节 def padding(data): #定义分块长度为 16字节 AES_BLOCK_SIZE=16 padding_data=lambda data: data.encode() + (AES_BLOCK_SIZE - len(data) % AES_BLOCK_SIZE) * bytes([AES_BLOCK_SIZE - len(data) % AES_BLOCK_SIZE]) return padding_data(data) data='123456789' padding_data=padding(data) print(padding_data)
STEP 2:密钥扩展
根据AES的初始密钥,生成多个不同的轮密钥,根据官方文档中显示,AES128密钥需要通过10轮的扩展
这里可以查看官方文档:高级加密标准AES-FIPS197中文版.pdf (masol7.com)
官方文档中伪代码实现 方式如下:
根据我的理解,密钥扩展大概包括以下步骤:
1、将初始KEY编排成4字节的线性数组
2、先使用 RotWord() 进行执行循环移位
3、然后使用 SubWord()函数将编排好的4字节线性数组对应S盒然后输出
4、最后和给定轮常量进行异或
STEP 3:轮变化
首先看官方文档中加密部分的伪代码
轮变化过程主要经历SubBytes(字节替换 )、ShiftRows(行位移)、MixColumns(列混合)、AddRoundKey(轮密钥加密)
这里就不展开解释每个函数具体怎么实现的了 下面这个博主其实讲解的挺详细的,放上链接
AES加密算法原理的详细介绍与实现-CSDN博客
STEP 4:前九轮重复 STEP3 最后一轮不包含 MixColumns(列混合)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。