1.前言
AES 加密最常用的模式就是 ECB模式 和 CBC 模式,当然还有很多其它模式,他们都属于AES加密。ECB模式和CBC 模式俩者区别就是 ECB 不需要 iv偏移量,而CBC需要。
AES加解密算法的参数
参数 | 作用及数据类型 |
秘钥 | 加密的时候用秘钥,解密的时候需要同样的秘钥才能解出来; 数据类型为bytes |
明文 | 需要加密的参数; 数据类型为bytes |
模式 | aes 加密常用的有 ECB 和 CBC 模式(这两个模式最常见,还有其他模式);数据类型为aes类内部的枚举量 |
iv 偏移量 | 这个参数在 ECB 模式下不需要,在 CBC 模式下需要;数据类型为bytes |
2. ECB模式
针对ECB模式的加密解密,参数中有几个限制:
- 秘钥必须为16字节或者16字节的倍数的字节型数据。
- 明文必须为16字节或者16字节的倍数的字节型数据,如果不够16字节需要进行补全
2.1 短字符串加解密
如果需要加解密的是很短的额字符串,直接使用以下代码
from Crypto.Cipher import AES
password = b'1234567812345678' #秘钥,b就是表示为bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_ECB) #创建一个aes对象
# AES.MODE_ECB 表示模式是ECB模式
en_text = aes.encrypt(text) #加密明文
print("密文:",en_text) #加密明文,bytes类型
den_text = aes.decrypt(en_text) # 解密密文
print("明文:",den_text)
自测输出
密文: b'WU\xe0\x0e\xa3\x87\x12\x95\\]O\xd7\xe3\xd4 )'
明文: b'abcdefghijklmnhi'
Process finished with exit code 0
如果是BASE64编码的密文需要解密呢?
使用如下代码
from Crypto.Cipher import AES
import base64
password = b'1234567812345678'
aes = AES.new(password,AES.MODE_ECB)
# en_text = b"Pd04a4bt7Bcf97KEfgLGQw=="
en_text = "Pd04a4bt7Bcf97KEfgLGQw==".encode() #将字符串转换成bytes数据
en_text = base64.decodebytes(en_text) #将进行base64解码,返回值依然是bytes
den_text = aes.decrypt(en_text)
print("明文:",den_text.decode("gbk"))
因为无论是 utf8
和 gbk
编码,针对英文字符编码都是一个字符对应一个字节,所以这里**encode()**函数主要作用就是转换成bytes数据,然后使用base64进行解码。
自测输出
明文: 好好学习天天向上
Process finished with exit code 0
有一些AES加密,所用的秘钥,或者IV向量是通过 base64编码或者 hexstr编码后的。针对这种,首先要进行的就是进行解码,都转换回 bytes数据,再次强调,python实现 AES加密解密传递的参数都是 bytes(字节型) 数据。
hexstr,base64编码解码例子:
import base64
import binascii
data = "hello".encode()
data = base64.b64encode(data)
print("base64编码:",data)
data = base64.b64decode(data)
print("base64解码:",data)
data = binascii.b2a_hex(data)
print("hexstr编码:",data)
data = binascii.a2b_hex(data)
print("hexstr解码:",data)
自测输出:
base64编码: b'aGVsbG8='
base64解码: b'hello'
hexstr编码: b'68656c6c6f'
hexstr解码: b'hello'
Process finished with exit code 0
2.2 对二进制格式的密文进行解密
如果需要解密的是一个很长的二进制文件,那么可以使用以下代码(代码用chatgpt获得的,质量不错)
密钥要转为bytes格式
输入文件: xxx.zip.enc
输出文件:xxx.zip
from Crypto.Cipher import AES
import os
secret_key = b'xxxxxx' # Convert the secret key to bytes
input_file = 'xxx.zip.enc'
output_file = 'xxx.zip'
# Initialize the AES cipher with the secret key and ECB mode
cipher = AES.new(secret_key, AES.MODE_ECB)
# Get the size of the input file
file_size = os.path.getsize(input_file)
# Open the input and output files
with open(input_file, 'rb') as in_file, open(output_file, 'wb') as out_file:
# Read and decrypt the input file in chunks
while True:
chunk = in_file.read(AES.block_size)
if len(chunk) == 0:
break
out_chunk = cipher.decrypt(chunk)
out_file.write(out_chunk)
# Remove any padding from the output file
out_file.truncate(file_size - AES.block_size + len(out_chunk))
自测结果(考虑填充,AES的输出和输入长度一样)
3.CBC 模式
CBC模式与ECB模式的区别:AES.new() 解密和加密重新生成了aes对象,加密和解密不能调用同一个aes对象,否则会报错。为了防止这类错误,写代码无论是什么模式都重新生成AES对象。
代码
from Crypto.Cipher import AES
password = b'1234567812345678' #秘钥,b就是表示为bytes类型
iv = b'1234567812345678' # iv偏移量,bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_CBC,iv) #创建一个aes对象
# AES.MODE_CBC 表示模式是CBC模式
en_text = aes.encrypt(text)
print("密文:",en_text) #加密明文,bytes类型
aes = AES.new(password,AES.MODE_CBC,iv) #CBC模式下解密需要重新创建一个aes对象
den_text = aes.decrypt(en_text)
print("明文:",den_text)
自测结果
密文: b'\x93\x8bN!\xe7~>\xb0M\xba\x91\xab74;0'
明文: b'abcdefghijklmnhi'
Process finished with exit code 0
4. 填充模式
前面使用秘钥,还有明文,包括IV向量,都是固定16字节,也就是数据块对齐了。而填充模式就是为了解决数据块不对齐的问题,使用什么字符进行填充就对应着不同的填充模式。
填充模式
模式 | 意义 |
ZeroPadding | 用b’\x00’进行填充,这里的0可不是字符串0,而是字节型数据的b’\x00’ |
PKCS7Padding | 当需要N个数据才能对齐时,填充字节型数据为N、并且填充N个 |
PKCS5Padding | 与PKCS7Padding相似 |
no padding | 当为16字节数据时候,可以不进行填充,而不够16字节数据时同ZeroPadding一样 |
如果你写的python代码需要考虑填充模式,可以参考这一篇博客的代码。
5.最后
AES是常见非对称加密算法。