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