python(3.x) 實現AES 加解密

首先 安裝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

相關文章
相關標籤/搜索