首先 安裝cryptographypython
sudo pip3 install cryptography
確認安裝的是2.1.x版本 (1.x版本的api是不同的).api
文件頭部的聲明爲:安全
# coding: utf-8 import os from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import padding import base64 # 128bits block size aes_block_size = 16
咱們能夠生成一個隨機的密鑰:app
def get_random_key_readable(key_size=256): ''' get random key for symmetric encryption with key_size bits :param key_size: bit length of the key :return: bytes key ''' # length for urandom ulen = int(key_size/8/4*3) key = base64.b64encode(os.urandom(ulen)) return key
注意要使用密碼學安全的隨機方法os.urandom
.
這裏生成的是str而不是bytes, 爲了可讀性.dom
採用AES CBC 加密:測試
def aes_cbc_encrypt(message, key): ''' use AES CBC to encrypt message, using key and init vector :param message: the message to encrypt :param key: the secret :return: bytes init_vector + encrypted_content ''' iv_len = 16 assert type(message) in (str,bytes) assert type(key) in (str,bytes) if type(message) == str: message = bytes(message, 'utf-8') if type(key) == str: key = bytes(key, 'utf-8') backend = default_backend() iv = os.urandom(iv_len) cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) encryptor = cipher.encryptor() padder = padding.PKCS7(128).padder() padded_data = padder.update(message) + padder.finalize() enc_content = encryptor.update(padded_data) + encryptor.finalize() return iv + enc_content
內容加密前須要padding到128bit(16bytes)的整數倍長度纔可. cryptography有對應padding方法.
初始向量爲16bit長度. 返回初始向量+加密數據.加密
解密方法爲:code
def aes_cbc_decrypt(content, key): ''' use AES CBC to decrypt message, using key :param content: the encrypted content using the above protocol :param key: the secret :return: decrypted bytes ''' assert type(content) == bytes assert type(key) in (bytes, str) if type(key) == str: key = bytes(key, 'utf-8') iv_len = 16 assert len(content) >= (iv_len + 16) iv = content[:iv_len] enc_content = content[iv_len:] backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) unpadder = padding.PKCS7(128).unpadder() decryptor = cipher.decryptor() dec_content = decryptor.update(enc_content) + decryptor.finalize() real_content = unpadder.update(dec_content) + unpadder.finalize() return real_content
咱們能夠隨機生成一些message測試下加解密:orm
import random import unittest import time from app.libs.crypto_enc import * from app.libs.crypto_sign import * class TestAESEnc(unittest.TestCase): def test_aes_enc_dec(self): key = get_random_key_readable() print('start test_aes_enc_dec') total_len = 0 s = time.time() for i in range(100): mlen = random.randint(1, 1024*1024) total_len += mlen message = os.urandom(mlen) enc = aes_cbc_encrypt(message, key) dec = aes_cbc_decrypt(enc, key) self.assertEqual(message, dec, 'aes message len {} is not equal'.format(mlen)) e = time.time() print('total_len', total_len) print('total_time', e - s) print('speed', total_len / (e - s)) if __name__ == '__main__': unittest.main()
注意這裏的速度測試是不許的, 由於包含了urandom
的時間, 而這個方法比較耗時.
可是仍然能夠看到, AES的加解密速度是極快的.ip