小能豆

将 Javascript 加密算法转换为 Python

python

我有一个 JavaScript 加密算法,我正在尝试将其转换为 Python。我尝试研究算法,虽然它不是太复杂,但我无法完全理解并将其转换为 Python 代码。JavaScript代码是

var grecaptcha = [];
enc = function (a) {
var keyBytes = CryptoJS.PBKDF2('lrvq/wyDf6tqhxvg8NuIDQ==', 'Ivan Medvedev', { keySize: 48 / 4, iterations: 1000 });
// take first 32 bytes as key (like in C# code)
var key = new CryptoJS.lib.WordArray.init(keyBytes.words, 32);
// skip first 32 bytes and take next 16 bytes as IV
var iv = new CryptoJS.lib.WordArray.init(keyBytes.words.splice(32 / 4), 16);
// use the same encoding as in C# code, to convert string into bytes
var data = CryptoJS.enc.Utf16LE.parse(a);
var encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv });
$("#capBBC").val(encrypted.toString());
}

我能够编写的 Python 代码是

from Crypto.Protocol.KDF import PBKDF2
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def enc(a):
    key = PBKDF2("lrvq/wyDf6tqhxvg8NuIDQ==", "Ivan Medvedev", dkLen=48, count=1000)
    iv = key[32:]
    data = a.encode('utf-16le')

    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(pad(data, AES.block_size))

    return encrypted.hex()

print(enc("Cat"))

此代码引发以下异常

Traceback (most recent call last):
  File "C:\Users\Farhan Ahmed\Desktop\code\Python\Kiara Snickers\del.py", line 16, in <module>
    print(enc("Cat"))
  File "C:\Users\Farhan Ahmed\Desktop\code\Python\Kiara Snickers\del.py", line 11, in enc
    cipher = AES.new(key, AES.MODE_CBC, iv)
  File "C:\Users\Farhan Ahmed\AppData\Local\Programs\Python\Python310\lib\site-packages\Crypto\Cipher\AES.py", line 232, in new
    return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
  File "C:\Users\Farhan Ahmed\AppData\Local\Programs\Python\Python310\lib\site-packages\Crypto\Cipher\__init__.py", line 79, in _create_cipher
    return modes[mode](factory, **kwargs)
  File "C:\Users\Farhan Ahmed\AppData\Local\Programs\Python\Python310\lib\site-packages\Crypto\Cipher\_mode_cbc.py", line 274, in _create_cbc_cipher
    cipher_state = factory._create_base_cipher(kwargs)
  File "C:\Users\Farhan Ahmed\AppData\Local\Programs\Python\Python310\lib\site-packages\Crypto\Cipher\AES.py", line 93, in _create_base_cipher
    raise ValueError("Incorrect AES key length (%d bytes)" % len(key))
ValueError: Incorrect AES key length (48 bytes)

我不知道 dkLen 的价值应该是多少 提前感谢您的帮助。


阅读 146

收藏
2023-06-16

共1个答案

小能豆

在 CryptoJS 代码中,PBKDF2 返回的数据的前 32 个字节用作密钥,但在 Python 代码中是整个数据。
这是 48 字节大,与有效的 AES 密钥不对应,因此导致错误Incorrect AES key length (48 bytes)
此外,CryptoJS 代码中的密文返回的是 Base64 编码,而不是十六进制编码。

两者的可能解决方法是:

from Crypto.Protocol.KDF import PBKDF2
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64

def enc(a):
    keyIv = PBKDF2("lrvq/wyDf6tqhxvg8NuIDQ==", "Ivan Medvedev", dkLen=48, count=1000)
    key = keyIv[:32]
    iv = keyIv[32:]
    data = a.encode('utf-16le')

    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(pad(data, AES.block_size))

    return base64.b64encode(encrypted).decode('utf-8')

print(enc("Cat")) # CZ/1nUYEjhw4cFj08Yt1EQ==

它返回对应于 CryptoJS 代码的密文:

enc = function (a) {
    var keyBytes = CryptoJS.PBKDF2('lrvq/wyDf6tqhxvg8NuIDQ==', 'Ivan Medvedev', { keySize: 48 / 4, iterations: 1000 });
    // take first 32 bytes as key (like in C# code)
    var key = new CryptoJS.lib.WordArray.init(keyBytes.words, 32);
    // skip first 32 bytes and take next 16 bytes as IV
    var iv = new CryptoJS.lib.WordArray.init(keyBytes.words.splice(32 / 4), 16);
    // use the same encoding as in C# code, to convert string into bytes
    var data = CryptoJS.enc.Utf16LE.parse(a);
    var encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv });
    console.log(encrypted.toString());
}
enc("Cat")
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
2023-06-16