我想从Python后端获取IV到Sveltekit并用它来检查令牌是否相同。我使用 CryptoJS 和 pycryptodome。钥匙是一样的。
Python:
key = bytes(os.environ['KEY'], "utf-8")
iv = None
def generate_iv():
rand = os.urandom(4)
return struct.unpack('B' * len(rand), rand)
def encrypt(username, password):
global iv
if iv == None:
iv = generate_iv()
byte_data = b''.join(struct.pack('<I', index) for index in iv)
cipher = AES.new(key, AES.MODE_CBC, iv=byte_data)
data = f"{username}:{password}".encode()
padded_data = pad(data, AES.block_size, style='pkcs7')
encrypted_data = cipher.encrypt(padded_data)
print(base64.b64encode(encrypted_data).decode('utf-8'))
return base64.b64encode(encrypted_data).decode('utf-8')
class IV(APIView):
def get(self, request):
global iv
if iv == None:
iv = generate_iv()
return Response({'iv': f'{iv}'}, status=status.HTTP_200_OK)
JS:
let iv;
let numbers = [];
onMount(async () => {
const response = await fetch("http://127.0.0.1:8000/api/authapi/iv");
const data = await response.json();
const ivNumbers = data.iv.slice(1, -1).split(",").map(Number);
numbers = ivNumbers;
console.log(numbers);
iv = CryptoJS.lib.WordArray.create(new Uint8Array(numbers));
console.log(iv);
});
function encrypt(username, password) {
const key = "pR@QvK3oM&9t#S8X";
const data = `${username}:${password}`;
const encryptedData = CryptoJS.AES.encrypt(
data,
CryptoJS.enc.Utf8.parse(key),
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: iv,
}
);
console.log(encryptedData.toString());
return encryptedData.toString();
}
我的 API 响应如下:
{
"iv": "(246, 72, 5, 222)"
}
但是结果返回两个不同的值
数据:fA6ifpnK8NCLBRi7EYPf4zyDumGFeBwVnZC0vliN06I=(来自JS)
代币:PAwNhCecq4lJRKizJWCMhknk9gleAPRXV2owj29XD2k=(实际代币)
你正在做的事情不必要地复杂并且存在漏洞(因为你的 IV 仅使用 4 个随机字节)。
首先,AES 的 IV 大小为 16 字节:
os.urandom(16)
。Python 的示例实现:
import os
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
key = b'pR@QvK3oM&9t#S8X' #bytes(os.environ['KEY'], "utf-8")
iv = None
def generate_iv():
return os.urandom(16)
def encrypt(username, password):
global iv
if iv == None:
iv = generate_iv()
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
data = f"{username}:{password}".encode()
padded_data = pad(data, AES.block_size, style='pkcs7')
encrypted_data = cipher.encrypt(padded_data)
print("IV (Base64 encoded): " + base64.b64encode(iv).decode('utf-8'))
print("Ciphertext (Base64 encoded): " + base64.b64encode(encrypted_data).decode('utf-8'))
return base64.b64encode(encrypted_data).decode('utf-8')
encrypt('username', 'password')
可能的输出:
IV (Base64 encoded): R22EiVAgUqIo90WfLx2ppQ==
Ciphertext (Base64 encoded): Q5+74TQ7q3y51egBSVVebt6bty22mDolmIjlVldUR1Q=
JavaScript 的示例实现:
let iv = CryptoJS.enc.Base64.parse("R22EiVAgUqIo90WfLx2ppQ==");
function encrypt(username, password) {
const key = "pR@QvK3oM&9t#S8X";
const data = `${username}:${password}`;
const encryptedData = CryptoJS.AES.encrypt(
data,
CryptoJS.enc.Utf8.parse(key),
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: iv,
}
);
console.log(encryptedData.toString());
return encryptedData.toString();
}
encrypt('username', 'password');
与输出
Q5+74TQ7q3y51egBSVVebt6bty22mDolmIjlVldUR1Q=
与Python代码的输出一致。