本文为博主原创,未经许可严禁转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/117022776
最近手上有些需求用到了加密、解密,爬了很多坑,做个总结。
个人博客:https://blog.csdn.net/zyooooxie
简单介绍
MD5,message-digest algorithm 5(信息-摘要算法),不可逆;在字符串加密、请求报文 加密、数据库字段值 加密中经常用到;(实际校验过程: 收到请求后,服务端重新计算、比对, 如果相同-通过,不同-失败)
AES,高级加密标准(英语:Advanced Encryption Standard);AES加密的模式分 ECB, CBC, CTR, CFB, OFB;AES只有一个密钥,这个密钥既用来加密,也用于解密。【对称加密】
异或:加密是 明文与密钥 进行异或运算,得到 密文;解密是 密文与密钥 再次进行异或运算,还原成 明文。【一次加密,两次解密】
MD5加密-hashlib
需求
某接口参数:
参数名 必选 类型 说明
zySum 是 String MD5加密签名:id=value0&zy=value1&csdn=value2+qq153132336(最后的+不算)
代码
import hashlib
import datetime
def md5_func(test_str: str, key=None):
print('MD5加密前为 :' + test_str)
if key is None:
m = hashlib.md5()
else:
m = hashlib.md5(key.encode('utf-8'))
m.update(test_str.encode())
res = m.hexdigest()
print('MD5加密后为 :' + res)
return res
def cs():
# id=value0&zy=value1&csdn=value2+qq153132336
v0 = 'zyooooxie'
v1 = 'csdn'
v2 = 'test'
test_str = '&'.join(['id=' + v0, 'zy=' + v1, 'csdn=' + v2])
test_str += 'qq153132336'
md5_func(test_str)
AES加、解密-pycryptodome
我是直接下载、使用的pycryptodome;【Windows10】
安装过程的坑
1、pip install pycryptodome
在cmd执行时,报错:Microsoft Visual C++ 14.0 is required;
必须得去 下载安装包。
苦逼的是:安装包大小是3.7G,光下载就花了2个多小时。
2、安装 Visual Studio 2015
安装-安装结束(重启)-设置环境变量
安装 又是一个多小时。
3、再次 pip
打开安装文件夹-cmd-设置编码-set CL值-再执行pip。
这一步又花了我 一个多小时!
代码
AES/ECB/PKCS5Padding
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.Padding import unpad
import base64
def encrypt_func(encrypt_str: str, key: str = 'testTESTtestTEST') -> str:
BS = 16
# data_str进行 PKCS5Padding 的填充
new = pad(encrypt_str.encode("utf-8"), BS)
# 初始化加密器
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
# 进行aes加密
encrypt_aes = aes.encrypt(new)
# 用base64转成字符串形式
encrypted_text = base64.b64encode(encrypt_aes).decode()
Log.info(encrypted_text)
return encrypted_text
def decrypt_func(decrypt_str: str, key: str = 'testTESTtestTEST') -> str:
BS = 16
# 初始化加密器
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
# 用base64转成bytes
base64_decrypted = base64.decodebytes(decrypt_str.encode(encoding='utf-8'))
# 执行解密
decrypted_text = aes.decrypt(base64_decrypted)
# 去填充
new_decrypted_text = unpad(decrypted_text, BS)
# 转str
new_decrypted_str = new_decrypted_text.decode()
Log.info(new_decrypted_str)
return new_decrypted_str
^ 异或
需求
(其实,这一部分主要是 我自己发散思维想到的一些)
某接口参数 zy2 的加密方式是:
1,【第一版】某数字与8888异或后,再做AES解密(key=‘testTESTtestTEST’);
2,【第二版】某数字与8888异或后,将其结果(int) 转为字符数组;把数组的每个元素 与 7 再做异或,组合成为str;
这个版本 我觉得有问题:0-9 每个数字 和 7做异或,
def test():
print('数字 0-9 和 7 进行异或')
for a in range(10):
print('数字:{}'.format(a), '异或结果:{}'.format(a ^ 7))
得到的实际结果是:
数字 0-9 和 7 进行异或
数字:0 异或结果:7
数字:1 异或结果:6
数字:2 异或结果:5
数字:3 异或结果:4
数字:4 异或结果:3
数字:5 异或结果:2
数字:6 异或结果:1
数字:7 异或结果:0
数字:8 异或结果:15
数字:9 异或结果:14
那 按第二版 执行到最后的结果 假设为 121415451(str),解密反推时,怎么判断14、15是一个数字异或的结果(9、8),还是2个数字异或的结果(6和3、6和2)?
我没想通。
实际因为赶项目,这个加密被取消了。那我自己发散思维了!
3,【发散思维】某数字与8888异或后,将其结果 转为字符数组;把数组的每个元素 与 7 再做异或【元素为8时,结果为Z;元素为9时,结果为Y】,组合成为str;
4,【最终版】某数字与8888异或后,将其结果 转为字符数组;把数组的每个元素 与 7 再做异或【元素为8时,结果为 大写的26个英文字母的随机一个;元素为9时,结果为 小写的26个英文字母的随机一个】,组合成为str;
代码
def new_encrypt(test_int: int):
# test_list = [str(int(t) ^ 7) for t in str(test_int)]
test_list = list()
# 优化加密
for ti in str(test_int):
if int(ti) == 9: # res 为 14
# res = 'Z'
res = random.choice(ascii_lowercase)
elif int(ti) == 8: # res 为 15
# res = 'Y'
res = random.choice(ascii_uppercase)
else:
res = int(ti) ^ 7
test_list.append(res if isinstance(res, str) else str(res))
print(test_list)
res = ''.join(test_list)
print(res)
return res
def new_decrypt(test_str: str):
# abc_list = [str(int(i) ^ 7) for i in test_str]
abc_list = list()
for ts in test_str:
if ts in ascii_lowercase:
res = 9
elif ts in ascii_uppercase:
res = 8
else:
res = int(ts) ^ 7
abc_list.append(str(res))
print(abc_list)
res = int(''.join([*abc_list]))
print(res)
return res
随便使用某个数字 来验证下:
a = new_encrypt(83640969731621451856880722)
new_decrypt(a)
每次加密的结果 近乎100% 不同:
['Y', '4', '1', '3', '7', 'g', '1', 'l', '0', '4', '6', '1', '5', '6', '3', '2', '6', 'A', '2', '1', 'G', 'Z', '7', '0', '5', '5']
Y4137g1l046156326A21GZ7055
['8', '3', '6', '4', '0', '9', '6', '9', '7', '3', '1', '6', '2', '1', '4', '5', '1', '8', '5', '6', '8', '8', '0', '7', '2', '2']
83640969731621451856880722
['T', '4', '1', '3', '7', 'f', '1', 'l', '0', '4', '6', '1', '5', '6', '3', '2', '6', 'N', '2', '1', 'J', 'V', '7', '0', '5', '5']
T4137f1l046156326N21JV7055
['8', '3', '6', '4', '0', '9', '6', '9', '7', '3', '1', '6', '2', '1', '4', '5', '1', '8', '5', '6', '8', '8', '0', '7', '2', '2']
83640969731621451856880722
继续发散下思维
假设 某接口参数zy3 的值 就是1、2、3、5这4个固定元素 随机重复N次;
假设每个元素 重复出现3次,明文是123553212351,想要加密,咋简单实现呢?
按上面异或的思路(8、9对应大、小写英文字母的随机取值),1、2、3、5 对应某种方式计算后的随机值;
计算方式为取模
若key为7,
那1可以是10*7+1,可以是9*7+1,可以是11*7+1;
那2可以是200*7+2,可以是201*7+2,可以是199*7+2;
那3可以是3001*7+3,可以是3000*7+3,可以是2999*7+3;
那5可以是40000*7+5,可以是40001*7+5,可以是39999*7+5;
实际得出的结果就是:
1-71|64|78
2-1402|1409|1395
3-21010|21003|20996
4-280005|280012|279998
123553212351对应的结果可以是:71、1402、21010、280005、280012、21003、1409、64、1395、20996、279998、78;
【再复杂】对 三个转换后的值 做个随机取数 ;【再复杂plus】计算1、2、3、5的三个值时,取值更随机;
计算方式为直角坐标系的四个象限
若1为第二象限,第二象限角:2nπ+π/2<α< 2nπ+π;
若2为第三象限,第三象限角:2nπ+π<α<2nπ+3π/2;
若3为第一象限,第一象限角:2nπ<α<2nπ+π/2;
若5为第四象限,第四象限角:2nπ+3π/2<α<2nπ+2π;
举例,取n=6(key),故
第二象限角的取值范围是12.5π弧度 - 13π弧度,那1的值 就随机取(2250,2340),比如 2289|2300|2301;
第三象限角的取值范围是13π弧度 - 13.5π弧度,那2的值 就随机取(2340,2430),比如 2341|2342|2400;
第一象限角的取值范围是12π弧度 - 12.5π弧度,那3的值 就随机取(2160,2250),比如 2200|2201|2240;
第四象限角的取值范围是13.5π弧度 - 14π弧度,那5的值 就随机取(2430,2520),比如 2510|2511|2519;
123553212351对应的结果可以是:2289、2341、2200、2510、2511、2201、2342、2300、2400、2240、2519、2301;
【再复杂】对 三个转换后的值 做个随机取数 ;【再复杂plus】取1、2、3、5的三个值时,取得更随机;
这一部分的代码就不提供了。
本文链接:https://blog.csdn.net/zyooooxie/article/details/117022776
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie