使用python进行AES对称加密解密
常用的对称加密算法简介
有时需要对数据进行对称加解密,常用的有:
- DES(Data Encryption Standard,即数据加密标准)。
由于这种加密算法可以被暴力破解,所以已经不再安全。因此除了用它来解密以前的密文外,不应该再使用DES了。 - AES(Advanced Encryption Standard,即高级加密标准),已经取代DES成为新标准的对称加密算法。
AES加密法属于Rijndael加密法的子集。区别为:- 在AES的规格中,区块长度固定为128比特,密钥长度只有128,192和256比特三种选择。
- Rijndael的区块长度和密钥长度可以是位于128比特到256比特之间且为32比特整数倍的长度。
经典的对称区块加密模式
区块加密算法采用对称密钥,可以加密固定长度的较短(区块数量)的数据。为了处理任意长度的数据,加密算法必须指定加密模式。常用的加密模式如下:
- ECB mode (Electionic CodeBook)
最基本但是安全性最差的加密操作模式,不应该再使用此模式
。 - CBC mode(Ciphertext Block Chaining)
- CTR mode(Count TeR mode)
可用于并行运算, - CFB mode(Cipher FeedBack)
- OFB mode(Output FeedBack)
- OpenPGP mode
现代的对称区块加密模式
经典的加密模式,比如CBC mode只能保证机密性,但不能保证完整性。
基于这个原因,经典模式经常会和MAC算法(比如Crypto.Hash.HMAC)搭配使用,但是这种结合不够直观,有效和安全。
因此,有一些新的同时具有加密和验证完整性的模式设计出来:
- CCM mode(Counter with CBC-MAC)
只能和128比特的AES加密算法搭配使用。 - EAX mode(An AEAD mode designed for NIST)
- GCM mode(Galois/Counter Mode)
只能和128比特的AES加密算法搭配使用。 - SIV mode(Synthetic Initialization Vector (SIV))
只能和128比特的AES加密算法搭配使用。 - OCB mode(Offset CodeBook mode)
只能和128比特的AES加密算法搭配使用。
使用示例
安装依赖库
鉴于pycrypto已不再安全,建议使用pycryptodome。pycyrptodome 是pycrypto的分支,在安全性方面有较大提升。
pip install pycryptodome
示例
以经典的CBC模式为例
# -*- 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密文
以现代的OCB模式为例
# -*- 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
参考文章: