AES五种加密模式(CBC、ECB、CTR、OCF、CFB)
AES五种加密模式 密码有五种工作体制:1.电码本模式(Electronic Codebook Book (ECB
));2.密码分组链接模式(Cipher Block Chaining (CBC
));3.计算器模式(Counter (CTR
));4.密码反馈模式(Cipher FeedBack (CFB
));5.输出反馈模式(Output FeedBack (OFB
))。
暂缺
输出反馈模式(Output FeedBack (`OFB`))
python 使用AES加密
- 安装包命令
-
pip install pycryptodome
– >from Crypto.Cipher import AES
-
pip install pycryptodomex
– >from Cryptodome.Cipher import AES
四种加密的模版
## 电码本模式 ECB python3
# coding:utf-8
import base64
from Cryptodome.Cipher import AES
def aes_decode(data, key):
try:
aes = AES.new(str.encode(key), AES.MODE_ECB) # 初始化加密器
decrypted_text = aes.decrypt(base64.decodebytes(bytes(data, encoding='utf8'))).decode("utf8") # 解密
decrypted_text = decrypted_text[:-ord(decrypted_text[-1])] # 去除多余补位
except Exception as e:
pass
return decrypted_text
# 加密
def aes_encode(data, key):
while len(data) % 16 != 0: # 补足字符串长度为16的倍数
data += (16 - len(data) % 16) * chr(16 - len(data) % 16)
data = str.encode(data)
aes = AES.new(str.encode(key), AES.MODE_ECB) # 初始化加密器
return str(base64.encodebytes(aes.encrypt(data)), encoding='utf8').replace('\n', '') # 加密
if __name__ == '__main__':
# 密钥长度必须为16、24或32位,分别对应AES-128、AES-192和AES-256
key = 'asdfzxcvg0qwerab'
# 待加密文本
# todo 中文有待更新
data = "ASDFFNNNUNHNNUNNJUNUFNNDNND"
mi = aes_encode(data, key)
print("加密值:", mi)
print("解密值:", aes_decode(mi, key))
# python3 计算器模式 CTR
import Cryptodome.Cipher.AES as AES
import operator
from binascii import a2b_hex
from Cryptodome import Random
# 进行异或(bytes ^ bytes) 按位异或,迭代器
def xor_block(left, right):
return map(operator.xor, left, right)
# 转化为bytes类型
def int_to_bytes(x):
return x.to_bytes((x.bit_length() + 7) // 8, 'big')
# bytes转为十进制整数
def int_from_bytes(xbytes):
return int.from_bytes(xbytes, 'big')
class CTRCipher(object):
def __init__(self, key):
self._cipher = AES.new(key, AES.MODE_ECB)
self.block_size = AES.block_size
def encrypt(self, plainText, count):
count = bytes(count)
# 各个计数器值
counters = self._get_timers(count, len(plainText))
blocks = xor_block(self._cipher.encrypt(counters), plainText)
ciphertext = bytes(blocks)
return count + ciphertext[:len(plainText)]
def decrypt(self, cipherText):
blockSZ = self.block_size
# 加密和解密只有输入不同
pt = self.encrypt(cipherText[blockSZ:], cipherText[:blockSZ])
return pt[blockSZ:]
# 生成各个计数器的值
def _get_timers(self, iv, msgLen):
# iv: 计时器初值
# msgLen: 密文长度(明文)
blockSZ = self.block_size
blocks = int((msgLen + blockSZ - 1) // blockSZ)
timer = int_from_bytes(iv)
timers = iv
for i in range(1, blocks):
timer += 1
timers += int_to_bytes(timer)
return timers
if __name__ == '__main__':
iv = Random.new().read(AES.block_size)
ctr_key = "36f18357be4dbd77f050515c73fcf9f2"
decryptor = CTRCipher(a2b_hex(ctr_key))
# todo 中文尚未解决,
words = b"this is what i want"
a = decryptor.encrypt(words, iv)
print("CTR加密后的结果:", a)
print("CTR解密后", decryptor.decrypt(a))
## 密码分组链接模式 CBC python3
# coding:utf-8
import base64
from Cryptodome.Cipher import AES
def pkcs7padding(text):
"""
明文使用PKCS7填充
最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理
:param text: 待加密内容(明文)
:return:
"""
bs = AES.block_size # 16
length = len(text)
bytes_length = len(bytes(text, encoding='utf-8'))
# TODO:utf-8编码时,英文占1个字节,而中文占3个字节
padding_size = length if (bytes_length == length) else bytes_length
padding = bs - padding_size % bs
# TODO:chr(padding)看与其它语言的约定,有的会使用'\0'
padding_text = chr(padding) * padding
return text + padding_text
def pkcs7unpadding(text):
"""
处理使用PKCS7填充过的数据
:param text: 解密后的字符串
:return:
"""
try:
length = len(text)
unpadding = ord(text[length - 1])
return text[0:length - unpadding]
except Exception as e:
pass
def aes_encode(key, content):
"""
AES加密
key,iv使用同一个
模式cbc
填充pkcs7
:param key: 密钥
:param content: 加密内容
:return:
"""
key_bytes = bytes(key, encoding='utf-8')
iv = key_bytes
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
# 处理明文
content_padding = pkcs7padding(content)
# 加密
aes_encode_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8'))
# 重新编码
result = str(base64.b64encode(aes_encode_bytes), encoding='utf-8')
return result
def aes_decode(key, content):
"""
AES解密
key,iv使用同一个
模式cbc
去填充pkcs7
:param key:
:param content:
:return:
"""
try:
key_bytes = bytes(key, encoding='utf-8')
iv = key_bytes
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
# base64解码
aes_encode_bytes = base64.b64decode(content)
# 解密
aes_decode_bytes = cipher.decrypt(aes_encode_bytes)
# 重新编码
result = str(aes_decode_bytes, encoding='utf-8')
# 去除填充内容
result = pkcs7unpadding(result)
except Exception as e:
result = ""
return result
if __name__ == '__main__':
key = 'asdfqwerg01234ab'
# 对英文加密
data = 'Hello! 同个世界,同个梦想'
# 加密
mi = aes_encode(key, data)
# 打印,并解密
print(mi, aes_decode(key, mi))
## 密码反馈模式 CFB
from Cryptodome.Cipher import AES
from binascii import b2a_hex,a2b_hex
from Cryptodome import Random
class AesEncryption(object):
def __init__(self, key, mode=AES.MODE_CFB):
self.key = self.check_key(key)
self.mode = mode
self.iv = Random.new().read(AES.block_size)
def check_key(self, key):
# '检测key的长度是否为16,24或者32bytes的长度'
try:
if isinstance(key, bytes):
assert len(key) in [16, 24, 32]
return key
elif isinstance(key, str):
assert len(key.encode()) in [16, 24, 32]
return key.encode()
else:
raise Exception(f'密钥必须为str或bytes,不能为{type(key)}')
except AssertionError:
print('输入的长度不正确')
def check_data(self,data):
# '检测加密的数据类型'
if isinstance(data, str):
data = data.encode()
elif isinstance(data, bytes):
pass
else:
raise Exception(f'加密的数据必须为str或bytes,不能为{type(data)}')
return data
def encrypt(self, data):
# ' 加密函数 '
data = self.check_data(data)
cryptor = AES.new(self.key, self.mode,self.iv)
return b2a_hex(cryptor.encrypt(data)).decode()
def decrypt(self,data):
# ' 解密函数 '
data = self.check_data(data)
cryptor = AES.new(self.key, self.mode,self.iv)
return cryptor.decrypt(a2b_hex(data)).decode()
if __name__ == '__main__':
key = input('请输入key:')
data = '测试测试 中国是个伟大的国家'
aes = AesEncryption(key)
# 加密函数
e = aes.encrypt(data)
# 解密函数
d = aes.decrypt(e)
print(e,e)
欢迎大家来批评指正,共同学习,谢谢~