| import base64 |
| from functools import reduce |
| from random import choice |
| from string import digits, ascii_letters, punctuation |
| |
| from Crypto.Cipher import AES |
| |
| |
| def cbc_encrypt(plaintext: str, key: str): |
| """ |
| AES-CBC 加密 |
| key 必须是 16(AES-128)、24(AES-192) 或 32(AES-256) 字节的 AES 密钥; |
| 初始化向量 iv 为随机的 16 位字符串 (必须是16位), |
| 解密需要用到这个相同的 iv,因此将它包含在密文的开头。 |
| """ |
| block_size = len(key) |
| padding = (block_size - len(plaintext) % block_size) or block_size |
| |
| iv = reduce(lambda x, y: x + choice(digits + ascii_letters + punctuation), range(16), "") |
| mode = AES.new(key.encode(), AES.MODE_CBC, iv.encode()) |
| ciphertext = mode.encrypt((plaintext + padding * chr(padding)).encode()) |
| |
| return base64.b64encode(iv.encode() + ciphertext).decode() |
| |
| |
| def cbc_decrypt(ciphertext: str, key: str): |
| """ |
| AES-CBC 解密 |
| 密文的前 16 个字节为 iv |
| """ |
| ciphertext = base64.b64decode(ciphertext) |
| mode = AES.new(key.encode(), AES.MODE_CBC, ciphertext[:AES.block_size]) |
| plaintext = mode.decrypt(ciphertext[AES.block_size:]).decode() |
| return plaintext[:-ord(plaintext[-1])] |
| |
| |
| if __name__ == '__main__': |
| key = "hwWe\mS2`kvu8,z/|hvop7^~)ZUgQhHT" // 32位 AES-256 |
| |
| ciphertext = cbc_encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}', key) |
| print(ciphertext) |
| |
| plaintext = cbc_decrypt(ciphertext, key) |
| print(plaintext) |