有时需要对数据进行对称加解密,常用的有:
区块加密算法采用对称密钥,可以加密固定长度的较短(区块数量)的数据。为了处理任意长度的数据,加密算法必须指定加密模式。常用的加密模式如下:
不应该再使用此模式
。经典的加密模式,比如CBC mode只能保证机密性,但不能保证完整性。
基于这个原因,经典模式经常会和MAC算法(比如Crypto.Hash.HMAC)搭配使用,但是这种结合不够直观,有效和安全。
因此,有一些新的同时具有加密和验证完整性的模式设计出来:
鉴于pycrypto已不再安全,建议使用pycryptodome。pycyrptodome 是pycrypto的分支,在安全性方面有较大提升。
pip install pycryptodome
# -*- coding:utf-8 -*-
import json
from base64 import b64encode,b64decode
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
from Crypto.Random import get_random_bytes
class AESClassicCipher:
def __init__(self, key):
self.bs = AES.block_size
self.key = key
self.mode = AES.MODE_CBC
def encrypt(self, data):
cipher = AES.new(self.key, self.mode)
ct_bytes = cipher.encrypt(pad(data, self.bs))
iv = b64encode(cipher.iv).decode('utf-8')
ct = b64encode(ct_bytes).decode('utf-8')
return json.dumps({'iv':iv, 'ciphertext':ct})
def decrypt(self, json_input):
try:
b64 = json.loads(json_input)
iv = b64decode(b64['iv'])
ct = b64decode(b64['ciphertext'])
cipher = AES.new(self.key, self.mode, iv)
plaintext = unpad(cipher.decrypt(ct), self.bs)
return plaintext.decode('utf-8')
except (ValueError, KeyError) as err:
print("Incorrect decryption ", err)
return None
if __name__ == "__main__":
data = "你的CBC密文".encode('utf-8')
key = get_random_bytes(16)
aes_cipher = AESClassicCipher(key)
encrypt_reuslt = aes_cipher.encrypt(data)
print("Encryption was: ", encrypt_reuslt)
plaintext = aes_cipher.decrypt(encrypt_reuslt)
print("The message was: ", plaintext)
输出结果为
Encryption was: {"iv": "B6VyPVmqTvpa9deaZgCGxg==", "ciphertext": "UJormRNFuE/oHynbtIVCIw=="}
The message was: 你的CBC密文
# -*- coding:utf-8 -*-
import json
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
class AESModernCipher:
def __init__(self, key):
self.bs = AES.block_size
self.key = key
self.mode = AES.MODE_OCB
self.json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ]
def encrypt(self, header, data):
header = header
cipher = AES.new(self.key, self.mode)
cipher.update(header)
ciphertext, tag = cipher.encrypt_and_digest(data)
json_v = [ b64encode(x).decode('utf-8') for x in [cipher.nonce, header, ciphertext, tag] ]
return json.dumps(dict(zip(self.json_k, json_v)))
def decrypt(self, json_input):
try:
b64 = json.loads(json_input)
jv = {k:b64decode(b64[k]) for k in self.json_k}
cipher = AES.new(self.key, self.mode, nonce=jv['nonce'])
cipher.update(jv['header'])
plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag'])
return plaintext.decode('utf-8')
except (ValueError, KeyError) as err:
print("Incorrect decryption ", err)
return None
if __name__ == "__main__":
data = "你的OCB密文".encode('utf-8')
key = get_random_bytes(16)
header = b'header'
aes_cipher = AESModernCipher(key)
encrypt_reuslt = aes_cipher.encrypt(header, data)
print("Encryption was: ", encrypt_reuslt)
plaintext = aes_cipher.decrypt(encrypt_reuslt)
print("The message was: ", plaintext)
输出结果为:
Encryption was: {"nonce": "Sa8Fah2cNmMnIST22XL2", "header": "aGVhZGVy", "ciphertext": "sQqARVVaflyuyB0BV6FE", "tag": "BBMDIbVbjv7lVCYBWIuOdw=="}
The message was: 你的OCB密文
from Crypto.Cipher import AES
运行上面语句会报错:
from Crypto.Cipher import AES
ModuleNotFoundError: No module named ‘Crypto’
可能原因是安装有crypto, pycrypto, pycryptodome中的多个库。
解决办法:先将其全部卸载,然后再重新安装 pycryptodome.
pip uninstall crypto pycrypto pycryptodome
pip install pycryptodome
参考文章: