Python 实现 AES 对称加密

前言

当原子系统很多 (非微服务),而且各个原子系统之间需要相互调用,这时就需要保证两个系统之间的认证、以及数据加密。

这个时候就需要用到对称加解密了

选择

对于如何选择合适的加密算法,可以参考一下下面这篇文章

如何选择 AES 加密模式(CBC ECB CTR OCB CFB)?

最后我选择了两种方式分别来测试和实现 CBCOCB

另外 pycrypto 已经不再安全,建议使用 pycryptodome,它是 pycrypto 的分支,在安全性方面有较大提升。

1
pip install pycryptodome

CBC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 AesCbc:
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 = "需要加密的数据".encode('utf-8')
key = get_random_bytes(16) # Bytes

aes_cipher = AesCbc(key)

encrypt_reuslt = aes_cipher.encrypt(data)
print("密文: ", encrypt_reuslt)

plaintext = aes_cipher.decrypt(encrypt_reuslt)
print("原文: ", plaintext)

结果:

1
2
密文:  {"iv": "K8xL41sI3UoXaeWohUuZEA==", "ciphertext": "fLGcOq43vTZc9x3HX8Q9Nv82cwVT6WNTj5mcpuPEckw="}
原文: 需要加密的数据

OCB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import json
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

class AesOcb:
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(err)
return None

if __name__ == "__main__":
data = "需要加密的数据".encode('utf-8')
key = get_random_bytes(16) # Bytes
header = b'header'

aes_cipher = AesOcb(key)

encrypt_reuslt = aes_cipher.encrypt(header, data)
print("密文: ", encrypt_reuslt)

plaintext = aes_cipher.decrypt(encrypt_reuslt)
print("原文: ", plaintext)

结果:

1
2
密文:  {"nonce": "9Wd6sA1QGSdjXHu1zACA", "header": "aGVhZGVy", "ciphertext": "tyaCFrLuriy6F3xJqs0CehNWe3g7", "tag": "IqDrP9zX00aZMRe7DuCRzQ=="}
原文: 需要加密的数据