https://pypi.org/project/pycryptodomex/ 安装目录为:
Cryptodomehttps://pypi.org/project/pycryptodome/ 安装目录为:Crypto,同pycrypto模块一样,因此建议安装pycryptodomex
**_python3 -m pip install pycryptodomex_**
一 传统模式
1 ECB MODE
https://www.pycryptodome.org/en/latest/src/cipher/classic.html#ecb-mode-1
- Electronic Codebook Book, 电码本模式
- 数据加密前需要pad, 默认为
pkcs7, 将数据补全为block_size的整数倍
Python
import jsonimport base64from Cryptodome.Cipher import AESfrom Cryptodome.Util import Padding# key = AES.get_random_bytes(16)key = ('A' * 16).encode() # 16 bytes, 即为AES-128 (16 * 8 bits)data = json.dumps(dict(name='zoro', age=18)).encode()pad_data = Padding.pad(data, AES.block_size)mode = AES.MODE_ECB # AES-128-ECBcipher = AES.new(key, mode)cy_bytes = cipher.encrypt(pad_data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('ECB base64:', ct)cipher = AES.new(key, mode)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(Padding.unpad(dec_message, AES.block_size).decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAECB base64: BkA+I8H+dwwcUCdis5EGYcGnm9eHpqz6zEc3Qa71U5Y=Parsed: {'name': 'zoro', 'age': 18}'''
JavaScript
var key = 'AAAAAAAAAAAAAAAA' // 不能直接使用原始的KEY,需要用Utf8解码var key = CryptoJS.enc.Utf8.parse('AAAAAAAAAAAAAAAA');var encrypted = 'BkA+I8H+dwwcUCdis5EGYcGnm9eHpqz6zEc3Qa71U5Y=';var pt = CryptoJS.AES.decrypt(encrypted, key, {mode: CryptoJS.mode.ECB,}).toString(CryptoJS.enc.Utf8);console.log(JSON.parse(pt));// {name: 'zoro', age: 18}
2 CBC MODE
https://www.pycryptodome.org/en/latest/src/cipher/classic.html#cbc-mode-1
- Cipher Block Chaining, 密码分组链接模式
- 数据加密前需要pad
- 数据加密时,可指定IV,默认会自动生成随机IV
- 解密时需要KEY + IV
Python
import jsonimport base64from Cryptodome.Cipher import AESfrom Cryptodome.Util import Paddingkey = ('A' * 16).encode()data = json.dumps(dict(name='zoro', age=18)).encode()pad_data = Padding.pad(data, AES.block_size)mode = AES.MODE_CBCcipher = AES.new(key, mode)iv = cipher.ivcy_bytes = cipher.encrypt(pad_data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('CBC base64:', ct)cipher = AES.new(key, mode, iv=iv)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(Padding.unpad(dec_message, AES.block_size).decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAIV: diU6MY0+Y7+LH6asCIvrhQ==CBC base64: avCVt0G9tp4RC2bSAUrofV2DQU4Jggbgd7nMLG3im0E=Parsed: {'name': 'zoro', 'age': 18}'''# 固定IViv = ('B' * 16).encode() # 16 bytescipher = AES.new(key, mode, iv=iv)cy_bytes = cipher.encrypt(pad_data)ct = base64.b64encode(cy_bytes).decode()cipher = AES.new(key, mode, iv=iv)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(Padding.unpad(dec_message, AES.block_size).decode())'''输出KEY: AAAAAAAAAAAAAAAAIV: QkJCQkJCQkJCQkJCQkJCQg==CBC base64: QrG4mKyOKq3fBtDNWUE9CwCNjgDmz7YtDULyWnrW4cs=Parsed: {'name': 'zoro', 'age': 18}'''
JavaScript
var key = CryptoJS.enc.Utf8.parse('AAAAAAAAAAAAAAAA');var iv = CryptoJS.enc.Base64.parse('QkJCQkJCQkJCQkJCQkJCQg==');// or: var iv = CryptoJS.enc.Utf8.parse('BBBBBBBBBBBBBBBB');var encrypted = 'QrG4mKyOKq3fBtDNWUE9CwCNjgDmz7YtDULyWnrW4cs=';CryptoJS.AES.decrypt(encrypted, key, {mode: CryptoJS.mode.CBC,iv: iv,}).toString(CryptoJS.enc.Utf8);// '{"name": "zoro", "age": 18}'
3 CTR MODE
https://www.pycryptodome.org/en/latest/src/cipher/classic.html#ctr-mode-1
- Counter, 计算器模式
- 数据加密前无需pad
- 数据加密时,可指定nonce,默认会自动生成随机nonce,最大长度为15 (block_size-1 ?)
- 解密时需要KEY + nonce
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 24).encode()nonce = ('B' * 15).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_CTRcipher = AES.new(key, mode, nonce=nonce)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('CTR base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBBBBCTR base64: 2sC9xBr1Uk/qo7rkurfP9GfSZMkx6UVOZaC6Parsed: {'name': 'zoro', 'age': 18}'''
4 CFB MODE
https://www.pycryptodome.org/en/latest/src/cipher/classic.html#cfb-mode-1
- Cipher FeedBack, 密码反馈模式
- 数据加密前无需pad
- 数据加密时,可指定IV,默认会自动生成随机IV
- 解密时需要KEY + IV
Python
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16).encode()iv = ('B' * 16).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_CFBcipher = AES.new(key, mode, iv=iv)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('IV:', iv.decode())print('CFB base64:', ct)cipher = AES.new(key, mode, iv=iv)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAIV: BBBBBBBBBBBBBBBBCFB base64: ShJ+eeRSprU2s/ekM2ht4k9EBuvuUn1usyCHParsed: {'name': 'zoro', 'age': 18}'''
JavaScript
var key = CryptoJS.enc.Utf8.parse('AAAAAAAAAAAAAAAA');var iv = CryptoJS.enc.Utf8.parse('BBBBBBBBBBBBBBBB');var encrypted = 'ShJ+eeRSprU2s/ekM2ht4k9EBuvuUn1usyCH';CryptoJS.AES.decrypt(encrypted, key, {mode: CryptoJS.mode.CFB,iv: iv,}).toString(CryptoJS.enc.Utf8);// '{"name": "zoro", "age": 18}'
5 OFB MODE
https://www.pycryptodome.org/en/latest/src/cipher/classic.html#ofb-mode-1
- Output FeedBack, 输出反馈模式
- 数据加密前无需pad
- 数据加密时,可指定IV,默认会自动生成随机IV
- 解密时需要KEY + IV
import jsonimport base64from Cryptodome.Cipher import AESfrom Cryptodome.Util import Paddingkey = ('A' * 16).encode()iv = ('B' * 16).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_OFBcipher = AES.new(key, mode, iv=iv)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('IV:', iv.decode())print('OFB base64:', ct)cipher = AES.new(key, mode, iv=iv)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAIV: BBBBBBBBBBBBBBBBOFB base64: SsFUDz81sqBec/aIH0O9VeN6PUzGnzBnkTjXParsed: {'name': 'zoro', 'age': 18}'''
二 现代化模式
1 CCM MODE
https://www.pycryptodome.org/en/latest/src/cipher/modern.html#ccm-mode-1
- Counter with CBC-MAC,
- 数据加密前无需pad
- 数据加密时,可指定nonce,默认会自动生成随机nonce, nonce长度任意,推荐12
- 解密时需要 key + nonce
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16).encode()nonce = ('B' * 12).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_CCMcipher = AES.new(key, mode, nonce=nonce)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('CCM base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBCCM base64: QLkTB74YqRW4cjEqYKq1oUnyUnOR65LNqc4rParsed: {'name': 'zoro', 'age': 18}'''
2 EAX MODE
https://www.pycryptodome.org/en/latest/src/cipher/modern.html#eax-mode-1
- key + nonce
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16).encode()nonce = ('B' * 12).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_EAXcipher = AES.new(key, mode, nonce=nonce)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('EAX base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBEAX base64: 6exKCce+QEjnZZ4uD1GJoRv24cKNSZX/Bd/cParsed: {'name': 'zoro', 'age': 18}'''
3 GCM MODE
https://www.pycryptodome.org/en/latest/src/cipher/modern.html?highlight=GCM#ccm-mode-1
- Galois/Counter Mode, 伽罗瓦/计数器模式
- key + nonce
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16).encode()nonce = ('B' * 16).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_GCMcipher = AES.new(key, mode, nonce=nonce)cy_bytes = cipher.encrypt(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('GCM base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt(base64.b64decode(ct))pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBBBBBGCM base64: 6L6INq3hBjFmuazE/AxDygdKoCf0/Xs1MCr6Parsed: {'name': 'zoro', 'age': 18}'''
4 SIV MODE
https://www.pycryptodome.org/en/latest/src/cipher/modern.html#siv-mode-1
- Synthetic Initialization Vector
- key + nonce + tag
- key: 32 bytes
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16 * 2).encode()nonce = ('B' * 16).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_SIVcipher = AES.new(key, mode, nonce=nonce)cy_bytes, tag = cipher.encrypt_and_digest(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('tag:', tag)print('SIV base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt_and_verify(base64.b64decode(ct), tag)pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBBBBBtag: b'\xd8>\xd6\x81*\xce\xa0k\x19\x05\xf7\x82\r{\xa1\x11'SIV base64: jkdH0qf9Fy5KlymtehsLHGiQmX4rettnk16vParsed: {'name': 'zoro', 'age': 18}'''
5 OCB MODE
https://www.pycryptodome.org/en/latest/src/cipher/modern.html#ocb-mode-1
- Offset CodeBook
- key + nonce + tag
- tag: <=15 bytes
import jsonimport base64from Cryptodome.Cipher import AESkey = ('A' * 16).encode()nonce = ('B' * 15).encode()data = json.dumps(dict(name='zoro', age=18)).encode()mode = AES.MODE_OCBcipher = AES.new(key, mode, nonce=nonce)cy_bytes, tag = cipher.encrypt_and_digest(data)ct = base64.b64encode(cy_bytes).decode()print('KEY:', key.decode())print('nonce:', nonce.decode())print('tag:', tag)print('OCB base64:', ct)cipher = AES.new(key, mode, nonce=nonce)dec_message = cipher.decrypt_and_verify(base64.b64decode(ct), tag)pt = json.loads(dec_message.decode())print('Parsed:', pt)'''输出KEY: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnonce: BBBBBBBBBBBBBBBtag: b'\x13\x00g\xcc\xbb\x8aX{\xed\xe8\xf8\xd4h\xfa\x0f\xa1'OCB base64: znbNBeF5YVgihsx1S+IRP4d4cZiJK1PunOcfParsed: {'name': 'zoro', 'age': 18}'''
总结
| 模式 | 加密 | 解密 |
|---|---|---|
| ECB | KEY + PAD | UNPAD + KEY |
| CBC | KEY + PAD [ + IV ] | UNPAD + KEY + IV |
| CTR | KEY [ + nonce ] | KEY + nonce |
| CFB | KEY [ + IV ] | KEY + IV |
| OFB | KEY [ + IV ] | KEY + IV |
| CCM | KEY [ + nonce ] | KEY + nonce |
| EAX | KEY [ + nonce ] | KEY + nonce |
| GCM | KEY [ + nonce ] | KEY + nonce |
| SIV | KEY [ + nonce ] | KEY + nonce + tag |
| OCB | KEY [ + nonce ] | KEY + nonce + tag |
