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),在密码学 ...
随机推荐
- 高性能 Java 计算服务的性能调优实战
作者:vivo 互联网服务器团队- Chen Dongxing.Li Haoxuan.Chen Jinxia 随着业务的日渐复杂,性能优化俨然成为了每一位技术人的必修课.性能优化从何着手?如何从问题表 ...
- 使用kubeoperator安装的k8s集群配置Ingress规则有关说明
单独创建一个nginx 在 Deployment 里创建一个nginx工作负载,镜像用:nginx:alpine,并配置service为ClusterIP,然后添加Ingress规则 本地主机host ...
- 使用Metricbeat监控zookeeper遇到的问题
1.metricbeat中启动自动加载模块 metricbeat.config.modules: path: ${path.config}/modules.d/*.yml reload.enabled ...
- kubernetes给容器生命周期设置操作事件
Kubernetes支持预启动和预结束事件. Kubernetes在容器启动的时候发送预启动事件,在容器结束的时候发送预结束事件. 定义预启动和预结束事件操作 下面是Pod的配置文件: # cat l ...
- nginx干货文档
文档地址:https://files.cnblogs.com/files/sanduzxcvbnm/跟冰河学习Nginx技术.pdf
- .Net下的分布式唯一ID
分布式唯一ID,顾名思义,是指在全世界任何一台计算机上都不会重复的唯一Id. 在单机/单服务器/单数据库的小型应用中,不需要用到这类东西.但在高并发.海量数据.大型分布式应用中,这类却是构建整个系统的 ...
- 插件化编程之WebAPI统一返回模型
WebApi返回数据我们一般包裹在一个公共的模型下面的,而不是直接返回最终数据,在返回参数中,显示出当前请求的时间戳,是否请求成功,如果错误那么错误的消息是什么,状态码(根据业务定义的值)等等.我们常 ...
- Lombok好用是好用,就是容易踩坑,这份避坑指南请查收
序言 各位好啊,我是会编程的蜗牛,作为java开发者,我们平常在开发过程中,总是希望能够尽量少敲代码.这一方面,当然是为了偷懒,另一方面,当然也是为了代码看起来更加简洁一点,不断往编程规范上靠.然后其 ...
- 齐博x1如何调试查找全站的表单提交接口参数
H5.PC.WAP端的所有提交POST表单操作都是可以当作接口来用的. 比如我们通过PC或WAP浏览器打开相应要修改的界面,然后浏览器进入开发者模式,就可以追踪到所提交的变量参数.你在APP里边只要指 ...
- P 算法与 K 算法
P 算法与 K 算法 作者:Grey 原文地址: 博客园:P 算法与 K 算法 CSDN:P 算法与 K 算法 说明 P 算法和 K 算法主要用来解决最小生成树问题,即:不破坏连通性删掉某些边,使得整 ...