Python Web AES加密前后端对接

与前端对接登录接口的时候,约定用户密码使用AES加密方式进行存储。但是在测试对接时,发现前端生成的AES加密字符串,后端无法正常解密,前端和后端生成的加密字符串也不一致。经检查,key、iv、加密模式(CBC)、填充方式(PKCS7)、密码字符串编码方式都一样,但就是加密结果不一样。我们一起看看问题出在哪里吧。

1.找在线加密平台验证

AES在线加密/解密
我找了这个在线平台,首先进行加密字符串验证,确认谁的加密字符串有问题。经验证,后端加密字符串与在线加密平台生成结果一致,也可以正常解密。那就是前端加密代码存在理解不一致的地方了,但是前端反馈说,这个加密算法已经和其他平台进行过对接,一直使用的就是这套加密算法。这样我就只能自己动刀来找前后端的问题了,别的后端都能对接,我岂曰不能。

2.前端加密代码检查

前端在线验证平台
前端使用的加密库是CryptoJS,有在线测试平台,这就方便多了。前端代码拉来检查一遍,感觉key、iv、加密模式(CBC)、填充方式(PKCS7)、密码字符串编码方式都一样,执行加密后,加密结果就是不一样。

前端加密代码

import CryptoJS from "crypto-js";

export const AESencrypt = (str: string) => {
	//加密
	const iwxKey = "CBj6GIsL4h52nU1NolYDqAtR7wJ0KdSi";
	const key = CryptoJS.enc.Utf8.parse(iwxKey);
	const iv = CryptoJS.enc.Hex.parse("0000000000000000");
	const encRes = CryptoJS.AES.encrypt(str, key, {
		iv,
		mode: CryptoJS.mode.CBC,
		padding: CryptoJS.pad.Pkcs7,
	});
	return encRes.toString();
};

对比看下后端加密代码

# 密钥(key), 密斯偏移量(iv), CBC模式加密, 默认PKCS7填充
BLOCK_SIZE = 16  # Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

# utf8编码偏移
vi = '0000000000000000'
key = 'CBj6GIsL4h52nU1NolYDqAtR7wJ0KdSi'

def aes_encrypt(data):
    data = pad(data)
    # 字符串补位
    cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
    encryptedbytes = cipher.encrypt(data.encode('utf8'))
    # 加密后得到的是bytes类型的数据,使用Base64进行编码,返回byte字符串
    encodestrs = base64.b64encode(encryptedbytes)
    # 对byte字符串按utf-8进行解码
    enctext = encodestrs.decode('utf8')
    return enctext

在咬文嚼字之后,才发现iv编码前后端是不一致的,
前端为16进制字符串
const iv = CryptoJS.enc.Hex.parse("0000000000000000")
后端为utf-8编码字符串
vi.encode('utf8')
尽管在调试可视化查看或者输出时,都显示为0,但是不同编码的存储值应该是不一样的,因此影响了加密结果。

3.vi编码调整

找到问题了,这就什么都好说了,前端调整或者后端调整,都不是什么大问题。

前端调整

import CryptoJS from "crypto-js";

export const AESencrypt = (str: string) => {
	//加密
	const iwxKey = "CBj6GIsL4h52nU1NolYDqAtR7wJ0KdSi";
	const key = CryptoJS.enc.Utf8.parse(iwxKey);
    const iv = CryptoJS.enc.Utf8.parse("0000000000000000"); //更换iv编码格式
	// const iv = CryptoJS.enc.Hex.parse("0000000000000000");
	const encRes = CryptoJS.AES.encrypt(str, key, {
		iv,
		mode: CryptoJS.mode.CBC,
		padding: CryptoJS.pad.Pkcs7,
	});
	return encRes.toString();
};

后端调整

# python没有找到直接进行字符串转16进制编码的方式,这里直接手动设置为16进制字节了
vi = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
def aes_decrypt(data):
    data = data.encode('utf8')
    encodebytes = base64.decodebytes(data)
    # 将加密数据转换位bytes类型数据
    cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi)
    text_decrypted = cipher.decrypt(encodebytes)
    # 去补位
    text_decrypted = unpad(text_decrypted)
    text_decrypted = text_decrypted.decode('utf8')
    return text_decrypted

当然了前后端有一端调整即可,总之来说,还是要保持加密参数一致,加密结果才能一致。涉及多端对接加密不一致问题,找一个中间平台来做验证,终归是靠谱的。

我没有创造知识,只是串联大佬们的经验,解决了自己的问题,记录下来。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python中的AES加密可以使用PyCryptodome库来实现。下面是一个简单的示例代码: ```python from Crypto.Cipher import AES import base64 # 加密函数 def aes_encrypt(key, data): # 将key和data转换为bytes类型 key = bytes(key, encoding='utf-8') data = bytes(data, encoding='utf-8') # 补全data长度为16的倍数 padding = 16 - len(data) % 16 data += bytes([padding]) * padding # 创建AES对象并进行加密 cipher = AES.new(key, AES.MODE_ECB) encrypted_data = cipher.encrypt(data) # 将加密后的数据进行base64编码并返回 return base64.b64encode(encrypted_data).decode('utf-8') # 解密函数 def aes_decrypt(key, encrypted_data): # 将key和encrypted_data转换为bytes类型 key = bytes(key, encoding='utf-8') encrypted_data = base64.b64decode(encrypted_data) # 创建AES对象并进行解密 cipher = AES.new(key, AES.MODE_ECB) decrypted_data = cipher.decrypt(encrypted_data) # 去除补全的数据并返回解密后的结果 padding = decrypted_data[-1] return decrypted_data[:-padding].decode('utf-8') # 测试代码 key = '1234567890123456' data = 'Hello, world!' encrypted_data = aes_encrypt(key, data) print('加密后的数据:', encrypted_data) decrypted_data = aes_decrypt(key, encrypted_data) print('解密后的数据:', decrypted_data) ``` 在上面的代码中,我们使用了ECB模式进行加密和解密。需要注意的是,ECB模式不是很安全,因为它没有使用IV(初始化向量),容易受到重放攻击。如果需要更高的安全性,可以考虑使用CBC模式或者其他更安全的模式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱在一瞬间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值