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