加解密系列之一常用AES五种加密模式python呈现

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)

欢迎大家来批评指正,共同学习,谢谢~

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值