Python3 实现 AES 加解密

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() 函数。

    • str通过encode()方法可以编码为指定的bytes
    • 反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法;
      Python3 实现 AES 加解密_第1张图片

    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()方法;

2、ascii 可见及不可见字符
在这里插入图片描述

3、内置函数:ord() 逆函数
ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。

你可能感兴趣的:(Python萌新)