使用 Python 做 AES 加密

855 阅读2分钟

关于秘钥:秘钥 key 长度可以是128、192、256 位

AES加密模式有:ECB、CBC、CFB、OFB等,这里我们只说 CBC 模式。

CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。

使用ECB模式

准备工作:因为是使用了pycrypto进行加密,所以要先安装

pip3 install pycrypto

加下来是加密的流程

  1. 处理秘钥

    使用哈希函数把key转成256位

    key = hashlib.sha256(key.encode()).digest()
    
  2. 填充明文

    明文的字节数,必须是128 bit的倍数。所以对于不符合长度的明文要进行填充。

    def __pad(self, plain_text):
        """ 填充要加密的明文,满足128bit的要求 """
        hex_text = plain_text.encode()
        number_of_bytes_to_pad = self.block_size - len(hex_text) % self.block_size
        ascii_string = chr(number_of_bytes_to_pad)
        padding_str = number_of_bytes_to_pad * ascii_string
        padded_plain_text = plain_text + padding_str
        return padded_plain_text
    
  3. 逆填充明文

    解密出来的明文,需要把填充的字符去掉,还原成原始的明文。

    def __unpad(self, plain_text):
        """ 解包,解掉填充的内容 """
        last_character = plain_text[len(plain_text)-1:]
        bytes_to_remove = ord(last_character)
        return plain_text[:-bytes_to_remove]
    
  4. 加密方法

    def encrypt(self, plain_text):
        plain_text = self.__pad(plain_text)
        iv = Random.new().read(self.block_size) # 生成偏移量
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        encrypted_text = cipher.encrypt(plain_text.encode())
        return base64.b64encode(iv+encrypted_text).decode("utf-8")
    

    CBC 模式还要需要一个偏移量iv,这里每次都随机生成一个。最后把iv和加密后的内容经过base64编码后返回。

  5. 解密方法

    def decrypt(self, encrypted_text):
        encrypted_text = base64.b64decode(encrypted_text)
        iv = encrypted_text[:self.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        plain_text = cipher.decrypt(encrypted_text[self.block_size:]).decode("utf-8")
        return self.__unpad(plain_text)
    

    经过base64解码后,拿到偏移量iv,解密即可。

需要说明的是,不一样的填充算法加解密出来的内容是不一样的。比如网上很多文章都是填充'\0',这时候就需要修改填充算法。

最后还是给出全部源码,毕竟也没多少:

# -*- coding: utf-8 -*-
import hashlib
from Crypto.Cipher import AES
import base64
from Crypto import Random

class AESCipher(object):
    def __init__(self, key):
        super().__init__()
        self.block_size = AES.block_size
        # 使用sha256来生成加密的key
        self.key = hashlib.sha256(key.encode()).digest()
    
    def __pad(self, plain_text):
        """ 填充要加密的明文,满足128bit的要求 """
        hex_text = plain_text.encode()
        number_of_bytes_to_pad = self.block_size - len(hex_text) % self.block_size
        ascii_string = chr(number_of_bytes_to_pad)
        padding_str = number_of_bytes_to_pad * ascii_string
        padded_plain_text = plain_text + padding_str
        return padded_plain_text
    
    def __unpad(self, plain_text):
        """ 解包,解掉填充的内容 """
        last_character = plain_text[len(plain_text)-1:]
        bytes_to_remove = ord(last_character)
        return plain_text[:-bytes_to_remove]

    def encrypt(self, plain_text):
        plain_text = self.__pad(plain_text)
        iv = Random.new().read(self.block_size) # 生成偏移量
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        encrypted_text = cipher.encrypt(plain_text.encode())
        return base64.b64encode(iv+encrypted_text).decode("utf-8")

    def decrypt(self, encrypted_text):
        encrypted_text = base64.b64decode(encrypted_text)
        iv = encrypted_text[:self.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        plain_text = cipher.decrypt(encrypted_text[self.block_size:]).decode("utf-8")
        return self.__unpad(plain_text)

if __name__ == '__main__':

    cipher = AESCipher('bbbbbbb')
    en_text = cipher.encrypt('ddd')
    print('加密后:', en_text)
    de_text = cipher.decrypt(en_text)
    print('解密后:', de_text)

结束

Hope this helps