程式碼

為了易於保存,所有金鑰、向量、輸出結果都是以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的時候會需要用到兩個隨機生產的東西

  1. 金鑰: 可為128 192 256 bits,金鑰長度越長越不容易被破解。
  2. 初始化向量: 只有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])]

參考資料