Python3 实现 AES 加解密
一、binascii 模块
它实现字节与 base64编码的16 进制表示的ASCII之间的转化。Base64编码,64指A-Z、a-z、0-9、+和/这64个字符,基于这 64 个可打印字符来表示二进制数据的表示方法,base64 仅仅是把二进制数据按照一定的算法转化为可见的 ascii,但不要作为加密行为。
为什么要使用base64:用于网络传输,二进制格式的数据无法直接在网络上传输,需要把这些二进制转化为文本字符后再进行网络传输,对于二进制数据(图片,音频,视频,语音等非文本字符),我们先用 base64 编码成文本字符,然后序列化后再通过网络发送。
所以,正规的流程是首先需要先用 base64 把图片数据编码为文本字符,然后序列化,最后通过网络发送出去;另一端机器拿到这些数据,先进行反序列化,然后用 base64 进行解码还原。
1、使用于字符串和ASCII的转化
b2a_hex 和 a2b_hex 需要类似字节的对象,python 中 bytes 和 str 两种类型之间的转换使用 encode()、decode() 函数。
2、网络传输Demo
import base64
import json
f = open("/root/tools/yy.png", "rb")
imgdata = f.read() # 二进制图片数据
f.close()
imgdatab64 = base64.b64encode(imgdata)
print(imgdatab64) # 被编码成了 base64 的可见文本字符
jsdata = json.dumps(imgdatab64)
'''
通过网络传输......,
对方机器收到后,先反序列化,最后用 base64 进行解码
'''
jsdata_recv = jsdata
imgdatab64 = json.loads(jsdata_recv)
imgdata = base64.b64decode(imgdatab64)
二、 pycryptodome 模块
PyCrypto是 Python 中密码学方面最有名的第三方软件包,提供了许多加密算法的使用,它的开发工作于2012年就已停止,该项目的分支PyCrytodome 取代了 PyCrypto。
AES 加密的参数
1、秘钥:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。(AES 加密有 AES-128、AES-192、AES-256 三种,分别对应三种密钥长度 128bits(16字节)、192bits(24字节)、256bits(32字节)。当然,密钥越长,安全性越高,加解密花费时间也越长。默认的是AES-128,其安全性完全够用。)
2、明文:需要加密的数据,字节长度需要是16位的倍数。
3、模式:AES 常用的ECB, CBC, CTR, CFB, OFB,从安全性角度考虑 CBC 加密方法,本文只介绍了CBC实现方法。
4、iv 偏移量:CBC 模式下需要
"""
- export passwd
Version: 0.1
Date: 2020-03-12
"""
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
from Crypto import Random
"""
采用AES对称加密
"""
# 密钥(key), 密斯偏移量(iv) CBC模式加密
class prpcrypt(object):
def __init__(self, key, iv):
self.key = key.encode()
self.mode = AES.MODE_CBC
self.iv = iv
def add_to_16(self, text):
# 这个方法是字符串补位,如果没有达到16,就用字符填充
BLOCK_SIZE = 16 # Bytes
text1 = text.encode()
par = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * (chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)).encode()
return par(text1)
def unpar(self, text):
# 和上面补位相反,在解密的时候,删除填充的字节
unpar = lambda s: s[:-ord(s[len(s) - 1:])]
return unpar(text)
def encrypt(self, data):
newdata = self.add_to_16(data)
mycipher = AES.new(self.key, self.mode, self.iv) # 使用key和iv初始化AES对象, 使用MODE_CFB模式
result = mycipher.encrypt(newdata) ##加密后得到的是bytes类型的数据
self.encodestrs = b2a_hex(result) #使用base64进行编码,返回byte字符串
return self.encodestrs.decode() #对byte字符串按utf-8进行解码
def derypt(self, passwd):
passwd1 = passwd.encode()
encodebytes = a2b_hex(passwd1) #将加密数据转换位bytes类型数据
mycipher = AES.new(self.key, self.mode, self.iv)
result = mycipher.decrypt(encodebytes)
print(len(result), result)
text_decrypted = self.unpar(result)
text_decrypted = text_decrypted.decode()
print(len(text_decrypted), text_decrypted)
if __name__ == '__main__':
key = '5c44c819appsapi0'
iv = Random.new().read(AES.block_size) # 生成长度等于AES块大小的不可重复的密钥向量
pe = prpcrypt(key, iv)
data = 'asC#gdl14zqpoB'
passwd = pe.encrypt(data) #加密
print("加密后的数据为:", passwd)
pe.derypt(passwd) #解密
报错1:
TypeError: a bytes-like object is required, not ‘str’
“类型错误:需要类似字节的对象,而不是字符串”。
python3和Python2在套接字返回值解码上有所区别
python的bytes和str两种类型之间的转换函数encode()、decode()即可!
str通过encode()方法可以编码为指定的bytes;
反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法;
3、内置函数:ord() 逆函数
ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。