程式碼
為了易於保存,所有金鑰、向量、輸出結果都是以Base64編碼。
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
46
|
from Crypto.Cipher import AES
from Crypto import Random
import base64
BS = AES.block_size
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
class AES_HELPER(object):
def __init__(self):
print 'init'
def key_generator(self, bits=256):
random = Random.new()
key = random.read( bits/8 )
return base64.b64encode(key)
def iv_generator(self):
'''
AES Initialization Vector is 128 bits(16 bytes).
'''
random = Random.new()
key = random.read( 16 )
return base64.b64encode(key)
def encrypt(self, b64key, b64iv, data):
key = base64.b64decode(b64key)
iv = base64.b64decode(b64iv)
cryptor = AES.new(key, AES.MODE_CBC, iv)
data = pad(data)
encrypted = cryptor.encrypt(data)
encrypted = base64.b64encode(encrypted)
return encrypted
def decrypt(self, b64key, b64iv, data):
key = base64.b64decode(b64key)
iv = base64.b64decode(b64iv)
cryptor = AES.new(key, AES.MODE_CBC, iv)
decrypted = base64.b64decode(data)
decrypted = cryptor.decrypt(decrypted)
decrypted = unpad( decrypted )
return decrypted
aes_helper = AES_HELPER()
|
使用上也蠻容易的
1
2
3
4
5
6
7
8
9
|
if __name__ == '__main__':
key = aes_helper.key_generator()
iv = aes_helper.iv_generator()
data = "Hello moto. I'm fire. Thank you. I got fired. Thank you. Madadabi meow meow Madadabi meow."
encrypted = aes_helper.encrypt(key, iv, data)
decrypted = aes_helper.decrypt(key, iv, encrypted)
print ('data: %s' % data )
print ('encrypted: %s' % encrypted )
print ('decrypted: %s' % decrypted )
|
Random的使用
在使用AES的時候會需要用到兩個隨機生產的東西
- 金鑰: 可為128 192 256 bits,金鑰長度越長越不容易被破解。
- 初始化向量: 只有128 bits的形式,為了避免同樣的文章在同一金鑰下會被加密為同樣密文,從而增加被破解風險。
這邊要特別注意的是必須使用pycrypto所提供的Random,而不能用python原生地random,不然亂數會不夠安全。
以下為產生金鑰的程式碼
1
2
3
4
5
6
7
|
from Crypto import Random
import base64
def key_generator(bits=256):
random = Random.new()
key = random.read( bits/8 )
return base64.b64encode(key)
|
使用random.read()來產生隨機的金鑰串,裡面的參數決定了金鑰串的長度,單位是bytes。
初始向量也是同樣的作法,只是這次要限制在128 bits(16 bytes)
Padding (PKCS5 / PKCS7)
這邊要特別注意有所謂的padding問題,在網路上找了一些解決的方法,以下是程式碼。
1
2
3
|
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
|
參考資料