python3实现AES加密
前言
这几天研究了一下 python 实现 AES 加密,有很多坑
AES 加密的参数及其条件
这个 AES 加密的主要坑就在于这些条件, 首先 aes 加密有一下几个参数
- 秘钥:加密的时候用秘钥,解密的时候需要同样的秘钥才能解出来
- 明文:需要加密的参数
- 模式:aes 加密常用的有 ECB 和 CBC 模式(我只用了这两个模式,还有其他模式)
- iv 偏移量:这个参数在 ECB 模式下不需要,在 CBC 模式下需要
需要输入这些参数才能返回一个密文
下面是重点
下面说一下这几个参数的条件:
- 秘钥:必须是16位字节或者24位字节或者32位字节(因为python3的字符串是unicode编码,需要 encode才可以转换成字节型数据)
- 明文:字节长度需要是16位的倍数
下面我用python3简单的方法实现:
from Crypto.Cipher import AES
import base64
password = '1234567890123456' #秘钥
text = '1234567890123456' #需要加密的内容
model = AES.MODE_ECB #定义模式
aes = AES.new(password,model) #创建一个aes对象
en_text = aes.encrypt(text) #加密明文
print(en_text)
en_text = base64.encodebytes(en_text) #将返回的字节型数据转进行base64编码
print(en_text)
en_text = en_text.decode('utf8') #将字节型数据转换成python中的字符串类型
print(en_text.strip())
输出
b'u|\xcd\x0c\xdc\\\x90\xea\xdb\xee\xec\xf68\xdd\x00\x00'
b'dXzNDNxckOrb7uz2ON0AAA==\n'
dXzNDNxckOrb7uz2ON0AAA==
这里有个问题就是密钥和加密的文本内容都必须是固定的16位(根据我前面说的参数要求)
所以下面优化的代码(将秘钥和需要加密的文本补成对应的位数)
from Crypto.Cipher import AES
import base64
def add_to_16(par):
par = par.encode() #先将字符串类型数据转换成字节型数据
while len(par) % 16 != 0: #对字节型数据进行长度判断
par += b'\x00' #如果字节型数据长度不是16倍整数就进行 补充
return par
password = '123456' #秘钥
text = '1' #需要加密的内容
model = AES.MODE_ECB #定义模式
aes = AES.new(add_to_16(password),model) #创建一个aes对象
en_text = aes.encrypt(add_to_16(text)) #加密明文
print(en_text)
en_text = base64.encodebytes(en_text) #将返回的字节型数据转进行base64编码
print(en_text)
en_text = en_text.decode('utf8') #将字节型数据转换成python中的字符串类型
print(en_text.strip())
这里简单的说一下几个存在的问题
- 其实上述代码我简单省略的进行补全到16位,而秘钥24位也是可以的,你可以自己写一个函数来进行秘钥的补全
- 为什么进行补全之前先进行 .encode() ? 首先 encode() 不加参数默认是以 utf8 编码的,另外先进行 encode 的原因是因为怕加密的文本中存在汉字,而汉字的 utf8 编码的字节长度是3(gbk对汉字的编码字节长度是2),所以为了防止补全的位数不正确,这里必须先进行转换(我看到很多别的文章先补全后进行转换的,而且还是拿空格补全的。。。)
- 不知道有没有发现,aes.encrypt() 在第一个程序中我传递的是字符串类型,第二个程序传递的是字节型数据,这个函数其实是既可以传递字符串数据类型也可以传递字节型数据的
上面的程序没有解密函数,所以我对整个加密解密进行了一个类的最终封装
from Crypto.Cipher import AES
import base64
class aescrypt():
def __init__(self,key,model,iv,encode_):
self.encode_ = encode_
self.model = {'ECB':AES.MODE_ECB,'CBC':AES.MODE_CBC}[model]
self.key = self.add_16(key)
if model == 'ECB':
self.aes = AES.new(self.key,self.model) #创建一个aes对象
elif model == 'CBC':
self.aes = AES.new(self.key,self.model,iv) #创建一个aes对象
#这里的密钥长度必须是16、24或32,目前16位的就够用了
def add_16(self,par):
par = par.encode(self.encode_)
while len(par) % 16 != 0:
par += b'\x00'
return par
def aesencrypt(self,text):
text = self.add_16(text)
self.encrypt_text = self.aes.encrypt(text)
return base64.encodebytes(self.encrypt_text).decode().strip()
def aesdecrypt(self,text):
text = base64.decodebytes(text.encode(self.encode_))
self.decrypt_text = self.aes.decrypt(text)
return self.decrypt_text.decode(self.encode_).strip('\0')
if __name__ == '__main__':
pr = aescrypt('12345','ECB','','gbk')
en_text = pr.aesencrypt('好好学习')
print('密文:',en_text)
print('明文:',pr.aesdecrypt(en_text))
时隔多天, 我终于用上了以上的代码,然后我发现我的代码是错误的,评论区也有指出
所以我又重新测试发现在ECB模式是没有问题的, 在使用CBC 模式的条件下, 不可以在类的构造函数里面构建 aes对象, 也就是说在CBC模式下 每一次加密和解密 都需要重新构建aes对象 self.aes = AES.new(self.key,self.model,iv), 否则加密和解密的结果就会不一致或者报错
另外就是关于 padding模式方面的问题
ZeroPadding
PKCS7Padding
PKCS5Padding
这几种模式的区别, 我也不从算法方面探讨了, 因为我发现当你用什么补全的时候, 解密回来的字符串里是包含补全使用的字符串的所以代码中用'\x00' 补全是没有问题的, 你用什么补全都可以(这里我用的是python,至于别的语言是不是这样我就不知道了)
最后一个点就是 关于base64编码的问题了,我也不知道这个是不是由于padding 模式区别导致的, 因为有的密文采用的是base64编码, 有点密文采用的是 hexstr编码, 反正无论采用什么编码,在真正加密和解密的时候是绝对会转换成 bytes类型的
所以我最终只做一个只是针对 bytes 的AES加密解密类
from Crypto.Cipher import AES
import base64
class Aescrypt():
def __init__(self,key,model,iv):
self.key = self.add_16(key)
self.model = model
self.iv = iv
def add_16(self,par):
if type(par) == str:
par = par.encode()
while len(par) % 16 != 0:
par += b'\x00'
return par
def aesencrypt(self,text):
text = self.add_16(text)
if self.model == AES.MODE_CBC:
self.aes = AES.new(self.key,self.model,self.iv)
elif self.model == AES.MODE_ECB:
self.aes = AES.new(self.key,self.model)
self.encrypt_text = self.aes.encrypt(text)
return self.encrypt_text
def aesdecrypt(self,text):
if self.model == AES.MODE_CBC:
self.aes = AES.new(self.key,self.model,self.iv)
elif self.model == AES.MODE_ECB:
self.aes = AES.new(self.key,self.model)
self.decrypt_text = self.aes.decrypt(text)
self.decrypt_text = self.decrypt_text.strip(b"\x00")
return self.decrypt_text
if __name__ == '__main__':
passwd = "123456781234567"
iv = '1234567812345678'
aescryptor = Aescrypt(passwd,AES.MODE_CBC,iv) # CBC模式
# aescryptor = Aescrypt(passwd,AES.MODE_ECB,"") # ECB模式
text = "好好学习"
en_text = aescryptor.aesencrypt(text)
print("密文:",en_text)
text = aescryptor.aesdecrypt(en_text)
print("明文:",text)
上面这段代码 你输入的 所有参数都应该是字符串或者 字节型数据, 并且输出的都是 字节型数据
如果进行一些编码转换可以在类的外部进行完成, 这里我就不写了, 到这里我才真正的明白为什么 python自己不封装一下这个算法, 确实可能的情况太多了, 这样还是比较灵活的。(其实进一步封装也是可以的, 就是判断输入的是base64字符串,还是hexstr,或者bytes, 然后在自定义一下输出,不过我是懒得弄了)
另外附上 base64 编码解码 和 hexstr 编码解码
import base64
import binascii
data = "hello".encode()
data = base64.b64encode(data)
print("base64编码:",data)
data = base64.b64decode(data)
print("base64解码:",data)
data = binascii.b2a_hex(data)
print("hexstr编码:",data)
data = binascii.a2b_hex(data)
print("hexstr解码:",data)
如果你真的认真的读了我的这篇文章, 我相信你肯定解决了你的问题, 如果不是这样可以评论区提出
python3实现AES加密的更多相关文章
- Python3使用AES加密的库函数PyCrypto、PyCryptodome
我们在网上查看Python爬虫教程的时候,细心的朋友会发现:很多网站为了降低服务器的请求压力都做了各式各样的反爬策略,浏览器通过http post请求服务器端数据时,传输的data字段很多都是经过加密 ...
- Python3.6 AES加密 pycrypto 更新为 pycryptodemo | TypeError: Object type <class 'str'> cannot be passed to C code
#!/usr/bin/env python# -*- coding:utf-8 -*-# @author: rui.xu# @update: jt.huang# 这里使用pycryptodemo库# ...
- 使用Python3进行AES加密和解密 输入的数据
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES, ...
- python3 执行AES加密方法
cmd执行命令:pip install pycryptodome # -*- coding: utf-8 -*- # __author__ = 'Carry' import base64 from C ...
- python3.6 安装第三方库 pyCryptodome 实现AES加密
起因 前端日子写完的Python入库脚本,通过直接读取配置文件的内容(包含了数据库的ip,数据库的用户名,数据库的密码),因为配置文件中的数据库密码是明文显示的,所以不太安全,由此对其进行加密. 编码 ...
- python3.6 实现AES加密的示例(pyCryptodome)
当然我也是通过官方推荐,使用下面命令去下载安装的,pip就是好用... pip install pycryptodome 撸码开始 废话不多说,直接上demo # from Crypto.Has ...
- java代码实现python2中aes加密经历
背景: 因项目需要,需要将一个python2编写的aes加密方式改为java实现. 1.源python2实现 from Crypto.Cipher import AES from binascii i ...
- 记一次Python与C#的AES加密对接
前言 这几天做自动化测试的同事找到我,说是帮她看看有个AES加密的问题要怎么处理. 大概就是文档中贴了一段C#的AES加密代码,然后她要翻译成python的版本,去做一些测试相关的工作. 在我印象中, ...
- Python3安装Crypto加密包
Python3安装Crypto加密包 下载链接 加密包地址 步骤 下载加密包,解压加密包到Python安装目录下Lib\site-packages目录中,尝试在Pycharm中导入 from Cryp ...
- 关于CryptoJS中md5加密以及aes加密的随笔
最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...
随机推荐
- 重新扫描磁盘.bat
工作需要,需要常常扫描磁盘, 以前是先调用磁盘管理器,然后使用alt+a,再按r,完成对磁盘的扫描 但是速度慢效率低 昨天帮朋友装台式电脑系统的时候,他说要给磁盘分区, 发现磁盘内有卷被占用,无法删除 ...
- bat脚本关闭、等待时间、启动程序、
@echo off ::关闭/杀死进程 @taskkill /f /IM Hos.exe ::等待10秒 start /min /w mshta vbscript:setTimeout("w ...
- 有偿提供ES 7.X和8.X 版本 的白金版和企业版 使用咨询服务
若有意向,可通过下方的邮箱发邮件进行咨询,非诚勿扰.. 邮箱地址:sandu12345@msn.cn
- Kubernetes 监控--Grafana
前面我们使用 Prometheus 采集了 Kubernetes 集群中的一些监控数据指标,我们也尝试使用 promQL 语句查询出了一些数据,并且在 Prometheus 的 Dashboard 中 ...
- Elasticsearch:使用_update_by_query更新文档
转载自: https://blog.csdn.net/UbuntuTouch/article/details/105564270 在很多的情况下,我们我们想更新我们所有的文档: 添加一个新的field ...
- centos yum安装docker
cd /etc/yum.repos.d/ mv CentOS-Base.repo CentOS-Base.repo_bak wget -O /etc/yum.repos.d/CentOS-Base.r ...
- 微信小程序js-时间转换函数使用
最近在做云开发博客小程序 采集微信发布的信息放入数据库会有createTime因此发现了不一样的地方 云函数可以直接使用 但是放到引导全局的app.js文件却是找不到该方法-->dateform ...
- Python模拟客户端
本机客户端 import socket # 获取到socket sk = socket.socket() # 获取到地址 ip 和 端口号 server端的 address = ('127.0.0.1 ...
- Linux Block模块之deadline调度算法代码解析
1 总体说明 Deadline调度器对一个请求的多方面特性进行权衡来进行调度,以期望既能满足块设备扇区的顺序访问又能兼顾到一个请求不会在队列中等待太久导致饿死.Deadline调度器为了兼顾这两个方面 ...
- 聊一聊被 .NET程序员 遗忘的 COM 组件
一:背景 1.讲故事 最近遇到了好几起和 COM 相关的Dump,由于对 COM 整体运作不是很了解,所以分析此类dump还是比较头疼的,比如下面这个经典的 COM 调用栈. 0:044> ~~ ...