python实现AES加密/解密

1. AES简介

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
在这里插入图片描述

名词含义
明文P没有经过加密的数据
秘钥K用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
AES加密函数设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
密文C经加密函数处理后的数据
AES解密函数设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。

AES只是个基本算法,实现AES有几种模式,主要有ECB、CBC、CFB等几种模式。CBC模式中还有一个偏移量参数IV。

AES加密有AES-128、AES-192和AES-256三种,分别对应三种密钥长度128位(16字节)、192位(24字节)和256位(32字节)。密钥越长,安全性越高,加密和解密时间也会更长。一般默认是128位,其安全性完全够用。

2. 加密/解密时,字节数不够时的处理

2.1 加密时

因为密钥是16字节,所以明文加密时,字符串不足16字节的倍数,则要补充个数,例如:少4个,要补chr(4)chr(4)chr(4)chr(4),少2个,要补chr(2)chr(2)。

chr(参数)中的参数是缺少的字节,要补全。这里为什么要补充chr(缺少位的ASCII码作为参数),是因为这样能更好的读取字符串最后字符时,知道有几个填充字符,从而能采用字符串切片操作而逆向清除填充字符。

实现方法:
明文字符串 + chr(16-len(明文字符串)%16) * (16 - len(明文字符串)%16)

# 1.自定义函数实现
def pad(data):
    text = data + chr(16 - len(data) % 16) * (16 - len(data) % 16)
    return text

# 2.用lambda匿名函数
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)

2.2 解密时

加密时字符串不足16字节倍数时,填充的字符是chr(缺少的字节数作为参数的),所以逆向清除填充的字符串,利用最后字符的ASCII码进行切片得出所需字符串。

实现方法:

# 1.自定义函数实现
def unpad(s):
    last_num = s[-1]
    text = s[:-last_num]
    return text

# 2.用lambda匿名函数
unpad = lambda s: s[:-s[-1]]

3. 加/解密用到的pyhton库

用到Crypto 和 base64,Crypto包安装方法:

pip install cryptodome

安装后,在使用的时候可能还会提示包找不到,可以去包所在的路径看下包文件名是不是Crypto,如果是crypto,则需要改下名字即可

base64为内置库,无需安装。
Base64是网络上最常见的用于传输8Bit字节码的编码方式,能实现二进制与字符之间编码的互转。所以说Base64就是把字符串以二进制编码/解码。其中,b64encode为编码,b64decode为解码

4. 加/解密的python实现

4.1 ECB模式加密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_ECB_Encrypt(data, key):   # ECB模式的加密函数,data为明文,key为16字节密钥
    key = key.encode('utf-8')
    data = pad(data)             # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_ECB)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')        # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
encrypt_data = aes_ECB_Encrypt(data, key)
print("待加密的字符是:{}\n秘钥为:{}\n加密后的密文为:{}".format(data, key, encrypt_data))

执行结果如下:

待加密的字符是:haha1234567890
秘钥为:1qaz@WSXabcdefgh
加密后的密文为:2Waxo/Owz/UdizFLDVcyiQ==

4.2 CBC模式加密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_CBC_Encrypt(data, key, iv):  # CBC模式的加密函数,data为明文,key为16字节密钥,iv为16字节的偏移量
    key = key.encode('utf-8')
    iv = iv.encode('utf-8')  # CBC 模式下的偏移量
    data = pad(data)  # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')  # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
iv = "1a2b3c4d5e6f7g8h"  # 偏移量
encrypt_data = aes_CBC_Encrypt(data, key, iv)
print("待加密的字符是:{}\n秘钥为:{}\n偏移量为:{}\n加密后的密文为:{}".format(data, key, iv, encrypt_data))

执行结果为:

待加密的字符是:haha1234567890
秘钥为:1qaz@WSXabcdefgh
偏移量为:1a2b3c4d5e6f7g8h
加密后的密文为:O2P4OqlNzEQHUpSfXE8KPw==

4.3 ECB模式解密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_ECB_Encrypt(data, key):   # ECB模式的加密函数,data为明文,key为16字节密钥
    key = key.encode('utf-8')
    data = pad(data)             # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_ECB)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')        # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
encrypt_data = aes_ECB_Encrypt(data, key)
print("待加密的字符是:{}\n秘钥为:{}\n加密后的密文为:{}".format(data, key, encrypt_data))


# 解密函数
def aes_ECB_Decrypt(data, key):  # ECB模式的解密函数,data为密文,key为16字节密钥
    key = key.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_ECB)  # 创建解密对象

    # decrypt AES解密  B64decode为base64 转码
    result = aes.decrypt(base64.b64decode(data))
    result = unpad(result)  # 除去补16字节的多余字符
    return str(result, 'utf-8')  # 以字符串的形式返回


decrypt_data = aes_ECB_Decrypt(encrypt_data, key)
print("\n待解密的字符是:{}\n秘钥为:{}\n解密后的字符为:{}".format(encrypt_data, key, decrypt_data))

执行结果:

待加密的字符是:haha1234567890
秘钥为:1qaz@WSXabcdefgh
加密后的密文为:2Waxo/Owz/UdizFLDVcyiQ==

待解密的字符是:2Waxo/Owz/UdizFLDVcyiQ==
秘钥为:1qaz@WSXabcdefgh
解密后的字符为:haha1234567890

4.4 CBC模式解密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_CBC_Encrypt(data, key, iv):  # CBC模式的加密函数,data为明文,key为16字节密钥,iv为16字节的偏移量
    key = key.encode('utf-8')
    iv = iv.encode('utf-8')  # CBC 模式下的偏移量
    data = pad(data)  # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')  # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
iv = "1a2b3c4d5e6f7g8h"  # 偏移量
encrypt_data = aes_CBC_Encrypt(data, key, iv)
print("待加密的字符是:{}\n秘钥为:{}\n偏移量为:{}\n加密后的密文为:{}".format(data, key, iv, encrypt_data))


# 解密函数
def aes_CBC_Decrypt(data, key, iv):  # CBC模式的解密函数,data为密文,key为16字节密钥
    key = key.encode('utf-8')
    iv = iv.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  # 创建解密对象

    # decrypt AES解密  B64decode为base64 转码
    result = aes.decrypt(base64.b64decode(data))
    result = unpad(result)  # 除去补16字节的多余字符
    return str(result, 'utf-8')  # 以字符串的形式返回


decrypt_data = aes_CBC_Decrypt(encrypt_data, key, iv)
print("\n待解密的字符是:{}\n秘钥为:{}\n偏移量为:{}\n解密后的字符为:{}".format(encrypt_data, key, iv, decrypt_data))

执行结果:

待加密的字符是:haha1234567890
秘钥为:1qaz@WSXabcdefgh
偏移量为:1a2b3c4d5e6f7g8h
加密后的密文为:O2P4OqlNzEQHUpSfXE8KPw==

待解密的字符是:O2P4OqlNzEQHUpSfXE8KPw==
秘钥为:1qaz@WSXabcdefgh
偏移量为:1a2b3c4d5e6f7g8h
解密后的字符为:haha1234567890
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jepson2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值