摘要&加密算法
摘要算法:一切从MD5开始
MD5是一个非常常见的摘要(hash)逻辑. 其特点就是小巧. 速度快. 极难被破解. 所以, md5依然是国内非常多的互联网公司选择的密码摘要算法.
这玩意不可逆. 所以. 摘要算法就不是一个加密逻辑.
相同的内容计算出来的摘要是一样的
不同的内容(哪怕是一丢丢丢丢丢不一样) 计算出来的结果差别非常大
在数学上. 摘要其实计算逻辑就是hash.
hash(数据) => 数字
1. 密码
2. 一致性检测
md5的python实现:
from hashlib import md5
obj = md5()
obj.update("you".encode("utf-8"))
# obj.update("are".encode('utf-8')) # 可以添加多个被加密的内容
bs = obj.hexdigest()
print(bs)
我们把密文丢到网页里. 发现有些网站可以直接解密. 但其实不然. 这里并不是直接解密MD5. 而是"撞库".
就是它网站里存储了大量的MD5的值. 就像这样:
而需要进行查询的时候. 只需要一条select语句就可以查询到了. 这就是传说中的撞库.
如何避免撞库: md5在进行计算的时候可以加盐. 加盐之后. 就很难撞库了.
from hashlib import md5
salt = "盐"
obj = md5(salt.encode("utf-8"))
obj.update("you".encode("utf-8"))
# obj.update("are".encode('utf-8')) # 可以添加多个被加密的内容
bs = obj.hexdigest()
print(bs)
扩展
不论是sha1, sha256, md5都属于摘要算法. 都是在计算hash值. 只是散列的程度不同而已. 这种算法有一个特性. 他们是散列. 不是加密. 而且, 由于hash算法是不可逆的, 所以不存在解密的逻辑.
from hashlib import sha1, sha256
sha = sha256(b'salt')
sha.update(b'alex')
print(sha.hexdigest())
对称加密(AES与DES)
加密相关理论可以参考 加密与CA证书
AES是一种对称加密,所谓对称加密就是加密与解密使用的秘钥是一个。
常见的对称加密: AES, DES, 3DES. 我们这里讨论AES。
安装:
pip install pycryptodome
AES 加密最常用的模式就是 CBC 模式和 ECB模式 ,当然还有很多其它模式,他们都属于AES加密。ECB模式和CBC 模式俩者区别就是 ECB 不需要 iv偏移量,而CBC需要。
"""
长度
16: *AES-128*
24: *AES-192*
32: *AES-256*
MODE 加密模式.
常见的ECB, CBC
ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或或操作后再加密,这样做的目的是增强破解难度。
"""
CBC加密案例(选择aes-128):
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
key = '0123456789abcdef'.encode() # 秘钥: 因为aes-128模式,所以必须16字节
iv = b'abcdabcdabcdabcd' # 偏移量:因为aes-128模式,所以必须16字节
text = 'alex is a monkey!' # 加密内容,因为aes-128模式,所以字节长度必须是16的倍数
# while len(text.encode('utf-8')) % 16 != 0: # 如果text不足16位的倍数就用空格补足为16位
# text += '\0'
text = pad(text.encode(), 16) # pad 用来补全长度
print("完整text:", text)
aes = AES.new(key, AES.MODE_CBC, iv) # 创建一个aes对象
en_text = aes.encrypt(text) # 加密明文
print("aes加密数据:::", en_text) # b"_\xf04\x7f/R\xef\xe9\x14#q\xd8A\x12\x8e\xe3\xa5\x93\x96'zOP\xc1\x85{\xad\xc2c\xddn\x86"
en_text = base64.b64encode(en_text).decode() # 将返回的字节型数据转进行base64编码
print(en_text) # X/A0fy9S7+kUI3HYQRKO46WTlid6T1DBhXutwmPdboY=
CBC解密案例:
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import unpad
key = '0123456789abcdef'.encode()
iv = b'abcdabcdabcdabcd'
aes = AES.new(key, AES.MODE_CBC, iv)
text = 'X/A0fy9S7+kUI3HYQRKO46WTlid6T1DBhXutwmPdboY='.encode() # 需要解密的文本
ecrypted_base64 = base64.b64decode(text) # base64解码成字节流
source = aes.decrypt(ecrypted_base64) # 解密
print("aes解密数据:::", source.decode())
print("aes解密数据:::", unpad(source, 16).decode())
在Python中进行AES加密解密时,所传入的密文、明文、秘钥、iv偏移量、都需要是bytes(字节型)数据。python 在构建aes对象时也只能接受bytes类型数据。
当秘钥,iv偏移量,待加密的明文,字节长度不够16字节或者16字节倍数的时候需要进行补全。
CBC模式需要重新生成AES对象,为了防止这类错误,无论是什么模式都重新生成AES对象就可以了。
非对称加密
非对称加密. 加密和解密的秘钥不是同一个秘钥. 这里需要两把钥匙. 一个公钥, 一个私钥. 公钥发送给客户端. 发送端用公钥对数据进行加密. 再发送给接收端, 接收端使用私钥来对数据解密. 由于私钥只存放在接受端这边. 所以即使数据被截获了. 也是无法进行解密的.
常见的非对称加密算法: RSA, DSA等等, 我们就介绍一个. RSA加密, 也是最常见的一种加密方案
- 创建公钥和私钥
from Crypto.PublicKey import RSA
# 生成秘钥
rsakey = RSA.generate(1024)
with open("rsa.public.pem", mode="wb") as f:
f.write(rsakey.publickey().exportKey())
with open("rsa.private.pem", mode="wb") as f:
f.write(rsakey.exportKey())
-
加密
data = "加密数据!" with open("rsa.public.pem", mode="r") as f: pk = f.read() # 构建钥匙对象 rsa_pk = RSA.importKey(pk) # 构建rsa算法对象 rsa = PKCS1_v1_5.new(rsa_pk) # 数据加密 result = rsa.encrypt(data.encode("utf-8")) # base64处理 base_result = base64.b64encode(result).decode("utf-8") print(base_result)
-
解密
data = "EVt+YXoDafYx+gvx+rbCrkZs0L0n1TG4Ime3CXitMWItxA0fM0IxY08vxvO7Lgfeb4YBidPkwntGC0KoBelx4M7SmbW+DiCvvIp/7rsfGC6lYfxXjdJ4t89I+VBwIPvex/+l+iR7AyL6FRyuv+kiSzRPUvR7kxeUE+4b6UEP3Gs=" # base64 解码 encrypt_data = base64.b64decode(data) # 构建钥匙对象 with open("rsa.private.pem", "r") as f: pk = f.read() rsa_pk = RSA.importKey(pk) # 构建rsa算法对象 rsa = PKCS1_v1_5.new(rsa_pk) # 数据解密 data = rsa.decrypt(encrypt_data, None) print(data.decode("utf-8"))