Python AES256加密

2021-03-26 修改:
本次修改尽量和其他语言中使用的关键保持一致,目前只做了PKCS7PADDING的填充方案和BASE64的输出格式

基础知识

# 在Linux操作系统下,Python3的默认环境编码变为了utf-8编码,所以在编写代码的时候,字符串大部分都是以utf-8处理
UTF-8:
1byte = 8bit
1个英文字符 = 1byte
1个中文字符 = 3byte

128bit = 16byte = 16个英文字符
192bit = 24byte = 24个英文字符
256bit = 32byte = 32个英文字符

AES256概念

AES是一种对称加密算法,对称指加密和解密使用同一个密钥; 256指密钥的长度是256bit,即32个英文字符的长度;密钥的长度决定了AES加密的轮数

AES256加密参数
  • 密钥: 一个32byte的字符串, 常被叫为key
  • 明文: 待加密的字符串;字节长度(按byte计算)必须是16的整数倍,因此,明文加密之前需要被填充
  • 模式: 加密模式,常用的有ECB、CBC;具体含义见参考链接
  • iv 偏移量: CBC模式下需要是16byte字符串; ECB下不需要

参考代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-


"""
pip install pycryptodome
ord(): 返回对应字符的ascii码
chr(): 返回ascii码对应的字符, ascii码可以用十进制,也可以用十六进制
"""


import base64
from Crypto.Cipher import AES
from Crypto.Cipher.AES import MODE_CBC, MODE_ECB


PKCS7PADDING = 0
PKCS5PADDING = 1

BASE64 = 0
HEX = 1


class AesCrypto:
    def __init__(self, key, mode=MODE_ECB, padding=PKCS7PADDING, iv=None, encode_type=BASE64):
        """
        :param key: 密钥, 32byte=>256, 16byte=>128, 24byte=>192
        :param mode: 加密模式
        :param iv: 16byte 长度字符串
        :param padding: 填充方式
        :param encode_type: 输出格式
        """

        self.key = key.encode()
        self.mode = mode
        self.encode_type = encode_type
        self.iv = iv
        if self.iv:
            self.iv = self.iv.encode()

        if padding == PKCS7PADDING:
            self.padding_func = self.pkcs7padding
            self.unpadding_func = self.unpadding
        else:
            raise Exception('padding is invalid')

    def pkcs7padding(self, text:str, bs=16):
        """明文使用PKCS7填充 """
        remainder = bs - len(text.encode()) % bs
        padding_text = chr(remainder) * remainder
        return text + padding_text

    def unpadding(self, text):
        """ 去掉填充字符 """
        remainder = text[-1]
        padding_text = ord(remainder) * remainder
        return text.rstrip(padding_text)

    def encrypt(self, text):
        """ 加密 """
        text = self.padding_func(text)
        # 注意:加密中的和解密中的AES.new()不能使用同一个对象,所以在两处都使用了AES.new()
        kwargs = {
            'key': self.key,
            'mode': self.mode
        }
        if self.mode == MODE_CBC:
            kwargs['iv'] = self.iv
        text = AES.new(**kwargs).encrypt(text.encode())
        if self.encode_type == BASE64:
            return base64.b64encode(text).decode()

    def decrypt(self, text):
        """ 解密 """
        if self.encode_type == BASE64:
            text = base64.b64decode(text.encode())
        kwargs = {
            'key': self.key,
            'mode': self.mode
        }
        if self.mode == MODE_CBC:
            kwargs['iv'] = self.iv
        text = AES.new(**kwargs).decrypt(text)
        text = self.unpadding_func(text.decode())
        return text

参考

posted @ 2020-11-26 11:52  ugvibib  阅读(3130)  评论(0编辑  收藏  举报