从Django后端获取IV

问题描述 投票:0回答:1

我想从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=(实际代币)

javascript django-rest-framework cryptojs pycryptodome
1个回答
0
投票

你正在做的事情不必要地复杂并且存在漏洞(因为你的 IV 仅使用 4 个随机字节)。

首先,AES 的 IV 大小为 16 字节:

os.urandom(16)

对于跨平台传输,最方便的是使用二进制到文本编码(例如 Base64)将 IV 转换为字符串(单独或与密文连接)。
CryptoJS 提供了一个 Base64 编码器 用于导入 Base64 编码数据。


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代码的输出一致。

© www.soinside.com 2019 - 2024. All rights reserved.