Python3+PyCryptodome实现各种加密算法教程
一、说明
PyCryptodome是python一个强大的加密算法库,可以实现常见的单向加密、对称加密、非对称加密和流加密算法。直接pip安装即可:
pip install pycryptodome
官网地址:https://pycryptodome.readthedocs.io/en/latest/index.html
二、Base64编码
2.1 base64编码说明
原理:
将要编码的内容按3字节为一组进行分组,最后一组不够3位的则补0(显然最多补两个0)
每组中每字节最高2位改成0不使用,原先各位的内容保持原有顺序往后移;最后在上一步中补了几个0就加几个等号以供解码时按等号个数删除0(经此操作原先3节字就变成了只使用低6位的4字节)
用途:一是SMTP中要以BASE64形式传输二进制文件,二是常用于将二进制数据转成可打印的ASCII码字符进行存储(下文各加密算法的密钥一般使用十六进制字符串形式存储,但也有以base64形式存储)。
其他:本质上讲Base64只能算是一种编码不能算是一种加密算法,PyCryptodome库也不支持。但从”Base64让人一下看不懂原本内容是什么“的角度讲你也不能说他完全不算加密,平时也经常用,我们就顺道讲一讲如何实现。
2.2 base64编码实现代码
import base64 # 编码b"123456",输出为b'MTIzNDU2'
base64.b64encode(b"") # 解码b'MTIzNDU2',输出为b"123456"
base64.b64decode(b'MTIzNDU2')
三、单向加密算法
3.1 单向加密算法说明
别称:单向加密算法,又称哈希函数、散列函数、杂凑函数、摘要算法,英文名One-way encryption algorithm。
原理:单向加密如其名只能加密不能解密(彩虹表攻击不是正经的解密),不能解密的原因是本质上并不是用IV(Initial Vector)去加密M输出M的密文,而是用M去加密IV输出IV的密文。
用途:消息认证摘要、内容或文档的数字指纹、口令存储。
其他:
单向加密又可以分为hash和hmac两大类,hmac和hash的算法是一样的,其实可以认为hmac就是hash加盐的形式(不过这盐值不是hash中常用的拼接在最前边或拼接在最后边,具体怎么拼接的我不太确定)。
一般来说标准库就挺好用时我们一般就直接用标准库,python的标准库就能容易地实现单向加密算法,所以单向加密我们使用标准库实现。
python中hash类算法使用hashlib库实现,hmac类算法使用hmac库实现。
3.2 标准库支持的单向加密算法
import hashlib # 注意输出结果中各算法使用大写和小写写了两遍
# 同时也是说到后边的书写中算法名大写或小写都是可以的
hashlib.algorithms_available
3.3 使用hashlib实现hash算法(以md5为例)
import hashlib # 实例化方法一,直接使用算法名;这种形式不完全支持hashlib.algorithms_available中的算法
# m = hashlib.md5()
# 实例化方法二,使用new方法;所有支持的算法名看上边hashlib.algorithms_available
m = hashlib.new("md5")
# update内是要加密的内容
# update使用+=,即连续多次update表示在原先内容上追加而不是替换
m.update(b"")
# 以十六进制字符串形式输出
m.hexdigest()
3.4 使用hmac实现hmac算法(以sha1为例)
import hmac # 实例化原形是hmac.new(key, msg=None, digestmod=None)
# key--加密用的盐值
# msg--要加密码的内容,可为空而后用update方法设置
# digestmod--加密算法,默认为md5,所有支持的算法名看上边hashlib.algorithms_available
m = hmac.new(b"",digestmod="sha1")
# update使用+=,即连续多次update表示在原先内容上追加而不是替换
# 但要注意所谓的+=是msg之间的+=,而不是key和msg之间的+=
# 即使用以下update后等于hmac.new(b"",b"", digestmod="sha1"),但不等于hmac.new(b"", digestmod="sha1")
m.update(b"")
# 以十六进制字符串形式输出
m.hexdigest()
四、对称加密算法
4.1 对称加密算法说明
别名:对称加密算法,又称密钥加密算法、单密钥算法、共享密钥算法,英文名Symmetric Encryption Algorithms。
原理:对称加密算法最关键的就是SP变换,S变换通过代替操作实现混乱(即消除统计信息),P变换通过换位操作实现扩散(即雪崩效应);加解密是使用同一个密钥的逆操作过程。
用途:对称加密可以还原内容,且代替和换位操作运算量不大,适用于大量内容的加解密。对称加密算法的缺点是加解密双方密钥分发困难。
其他:对称加密算法有ECB、CBC、CFB、OFB、CTR等等多种模式,各种模式的加密是有些区别的,比如ECB不需要IV、CBC等则需要IV、EAX则需要nonce和tag等等,所以实现不同模式时写法会有差别需要具体研究,不能完全照搬下边的例子。
4.2 对称加密算法实现代码(以AES算法CBC模式为例)
加密代码如下:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes # 要加密的内容
data = b""
# 随机生成16字节(即128位)的加密密钥
key = get_random_bytes(16)
# 实例化加密套件,使用CBC模式
cipher = AES.new(key, AES.MODE_CBC)
# 对内容进行加密,pad函数用于分组和填充
encrypted_data = cipher.encrypt(pad(data, AES.block_size)) # 将加密内容写入文件
file_out = open("encrypted.bin", "wb")
# 在文件中依次写入key、iv和密文encrypted_data
[file_out.write(x) for x in (key, cipher.iv, encrypted_data)]
对应解密代码如下:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad # 从前边文件中读取出加密的内容
file_in = open("encrypted.bin", "rb")
# 依次读取key、iv和密文encrypted_data,16等是各变量长度,最后的-1则表示读取到文件末尾
key, iv, encrypted_data = [file_in.read(x) for x in (16, AES.block_size, -1)] # 实例化加密套件
cipher = AES.new(key, AES.MODE_CBC, iv)
# 解密,如无意外data值为最先加密的b"123456"
data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
五、非对称加密算法
5.1 非对称加密算法说明
别称:非对称加密算法,又称公钥加密算法,英文名Asymmetric Cryptographic Algorithm。
原理:非对称加密依赖与明文经过与公钥进行数学运算可得出密文,而密文经过与密钥进行数学运算又可得到明文。
用途:非对称加密算法的优点是密钥分发简单,但缺点也是很明显的,其加解密过程依赖于数学运算运算量大所以加解密速度慢(另外同样的密钥强度其安全性弱于对称加密算法),其只适用于少量内容的加解密,最典型的就是https中用于完成对称密钥的交换。
5.2 非对称加密算法实现代码(以RSA为例)
生成密钥对代码如下:
from Crypto.PublicKey import RSA# 生成密钥对
key = RSA.generate(2048) # 提取私钥并存入文件
private_key = key.export_key()
file_out = open("private_key.pem", "wb")
file_out.write(private_key) # 提取公钥存入文件
public_key = key.publickey().export_key()
file_out = open("public_key.pem", "wb")
file_out.write(public_key)
加密代码如下:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP # 要加密的内容
data = b""
# 从文件中读取公钥
public_key = RSA.import_key(open("public_key.pem").read())
# 实例化加密套件
cipher = PKCS1_OAEP.new(public_key)
# 加密
encrypted_data = cipher.encrypt(data) # 将加密后的内容写入到文件
file_out = open("encrypted_data.bin", "wb")
file_out.write(encrypted_data)
解密代码如下:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP # 从私钥文件中读取私钥
private_key = RSA.import_key(open("private_key.pem", "rb").read())
# 实例化加密套件
cipher = PKCS1_OAEP.new(private_key)
# 从文件中读取加密内容
encrypted_data = open("encrypted_data.bin", "rb").read()
# 解密,如无意外data值为最先加密的b"123456"
data = cipher.decrypt(encrypted_data)
5.3 非对称加密算法签名实现(以RSA为例)
我一直以为私钥加密公钥解密和公钥加密私钥解密没什么两样,但首先一是和一个朋友说用私钥加密发送回来时她疑或说私钥可以加密吗,然后回公司又和领导说私钥加密公钥解密的时候他直接说私钥不能加密只能做签名。
首先说私钥加密公钥解密在数学原理上是可行的,而且所谓的数字签名其本质就是我用你的公钥可以解开这加密的内容说明这些内容就是你的,即数字签名和签名认证本质就是私钥加密公钥解密。
但另一方面,因为公钥是公开的所以私钥加密并不能起加密通信的作用,所以一般没有直接的私钥加密公钥解密的操作----但我不太明白为什么PyCryptodome这些库在程序试图使用私钥加密时直接报错拒绝执行(TypeError: This is not a private key),虽然没什么用,私钥加密也没有什么危害吧?
我们直接使用5.2中的公私钥,另外因为签名要传给签名校验的内容比较多,所以就两部分不分开写了,代码如下:
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA # 以下是签名部分
# 要签名的内容
data = b''
# 获取要签名的内容的HASH值。摘要算法是什么不重要,只要验证时使用一样的摘要算法即可
digest = SHA256.new(data)
# 读取私钥
private_key = RSA.import_key(open('private_key.pem').read())
# 对HASH值使用私钥进行签名。所谓签名,本质就是使用私钥对HASH值进行加密
signature = pkcs1_15.new(private_key).sign(digest) # 以下是签名校验部分
# 签名部分要传给签名校验部分三个信息:签名内容原文、摘要算法、HASH值签名结果
# 获取被签名的内容的HASH值。使用与签名部分一样的摘要算法计算
digest = SHA256.new(data)
# 读取公钥
public_key = RSA.import_key(open('public_key.pem').read()) try:
# 进行签名校验。本质上就是使用公钥解密signature,看解密出来的值是否与digest相等
# 相等则校验通过,说明确实data确实原先的内容;不等则校验不通过,data或signature被篡改
# 可能有人会想,如果我先修改data然后再用自己的私钥算出signature,是不是可以完成欺骗?
# 答案是不能,因为此时使用原先的公钥去解signature,其结果不会等于digest
pkcs1_15.new(public_key).verify(digest, signature)
print(f"The signature is valid.")
except (ValueError, TypeError):
print("The signature is not valid.")
六、流加密算法实现(以RC4为例)
6.1 流加密算法说明
别称:流加密算法,又称序列加密算法,英文名Stream cipher。
原理:流加密算法加密和解密也使用同一个密钥,所以从咬文嚼字来说他也属于对称加密算法。流加密算法与前边单向加密算法、对称加密算法、非对称加密算法的区别是前三者都是分组加密算法即一个分组使用同一个密钥,而流加密算法每一位都使用不同的密钥。
用途:流加密主要基于异或(xor)操作,运算相对简单,但安全性较低,没有很多的使用场景,最典型的是WEP上的使用但也正由于其安全性问题导致WEP的淘汰。
6.2 流加密算法实现代码(以RC4为例)
from Crypto.Cipher import ARC4
from Crypto.Hash import SHA
from Crypto.Random import get_random_bytes # 要加密的内容
data = b""
# 流加密密码长度是可变的,RC4为40到2048位
# 一般上使用一个字符串作为初始密钥,然后再用sha1等生成真正的密钥
# 我们这是直接点,随机生成16字节(即128位)作为密钥
key = get_random_bytes(16)
# 实例化加密套件
cipher = ARC4.new(key)
# 加密内容
encrypted_data = cipher.encrypt(data) # 注意在即便加解密像这里一样在同一文件里,解密时一定要重新实例化不然解密不正确
cipher = ARC4.new(key)
# 解密,如无意外data为前边加密的b"123456"
data = cipher.decrypt(encrypted_data)
参考:
https://pycryptodome.readthedocs.io/en/latest/src/examples.html#encrypt-data-with-aes
https://github.com/nemozqqz/pycrypto-sample/blob/master/RC4.py
Python3+PyCryptodome实现各种加密算法教程的更多相关文章
- Python3 turtle安装和使用教程
Python3 turtle安装和使用教程 Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x.纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数 ...
- 【Python】Python3纯代码极简教程
#!/usr/bin/python3 ''' Python3.6.x简单教程 示例.注释 交互式和脚本式编程 变量类型 数字(Number) 字符串(String) 列表(Li ...
- python3 pyqt5 和eric5配置教程
一.大纲内容: 1.预备PC环境: 2.预备安装程序: 2.1.下载Python3.2 2.2.下载PyQt4 2.3.下载Eric5 3.安装配置步骤: 3.1.安装Pyhon3.2 3.2.安装P ...
- 【Python3爬虫】Scrapy入门教程
Python版本:3.5 系统:Windows 一.准备工作 需要先安装几个库(pip,lxml,pywin32,Twisted,pyOpenSSL),这些都比较容易,如果使用的 ...
- Python3+SQLAlchemy+Sqlite3实现ORM教程
一.安装 Sqlite3是Python3标准库不需要另外安装,只需要安装SQLAlchemy即可.本文sqlalchemy版本为1.2.12 pip install sqlalchemy 二.ORM操 ...
- 【Python】Python3.4+Matplotlib详细安装教程
网上找了很多教程,这个还不错. 传送门:https://blog.csdn.net/xqf1528399071/article/details/52233895
- Mac上安装Python3虚拟环境(VirtualEnv)教程
如果已经安装好pip3,那么执行命令安装virtualenv环境 pip3 install virtualenv 安装完成检测版本是否安装成功 virtualenv --version 创建新目录 M ...
- 基于Centos7+Flask+Nginx+uWSGI+Python3的服务器网页搭建教程
之前完成了贴吧签到系统的搭建,笔者想将这个功能分享给更多人使用,所以尝试搭建了一个网页,一路遇到了很多问题,最终解决了,记录下过程分享给大家 首先安装 uWSGI ,和 Nginx 配套使用,具体用途 ...
- Python3教程—很经典可以快速上手
原文地址:https://www.runoob.com/python3/python3-tutorial.html Python 3 教程 Python 的 3.0 版本,常被称为 Python 30 ...
随机推荐
- 2019 农信互联java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.农信互联等公司offer,岗位是Java后端开发,因为发展原因最终选择去了农信互联,入职一年时间了,也成为了面 ...
- uni-app项目记录
1.如何定义一个全局属性 在App.vue 文件中,以 global.属性名= XXX; 定义 在其他页面就以 global.属性名来调用 或者在min.js 中使用 Vue.prototype 挂载 ...
- 【前端_React】npm常用命令
安装模块(包): //全局安装 $ npm install 模块名 -g //本地安装 $ npm install 模块名 //一次性安装多个 $ npm install 模块1 模块2 模块n -- ...
- Windows Server 2008 R2(x64) IIS7+PHP5.6.30(FastCGI)环境搭建
相关软件下载: 1.PHP下载地址: http://windows.php.net/downloads/releases/ 1.安装Microsoft Visual C++ 2012 Redistri ...
- js 驼峰命名和下划线互换
代码走你 // 下划线转换驼峰 function toHump(name) { return name.replace(/\_(\w)/g, function(all, letter){ return ...
- centos下的python无法打印中文
Python3中输出中文的方法如下: 方法一:在环境变量中,设置PYTHONIOENCODING=utf-8 以centos为例执行: export PYTHONIOENCODING=utf-8 方法 ...
- python中列表(list)函数及使用
序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类型,但最常见的是列表和元组. 序列 ...
- luoguP5495:Dirichlet 前缀和
题意:给定数组a[]的生成方式,然后b[i]=∑a[j] ,(i%j==0),求所有b[i]的异或和.所有运算%2^32; 思路:高维前缀和的思想,先筛出所有素数,然后把每个素数当成一维,那么分开考 ...
- HTTP协议之chunk,单页应用这样的动态页面,怎么获取Content-Length的办法
当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过Content-Length消息首部字段告诉客户端需要接收多少数据.但是如果是动态页面等时,服务器是不可能预先知 ...
- split分割字符串返回字符串数组
<script type="text/javascript"> var str='liu jin yu'; var str1=str.split(' '); docum ...