提问人:Neeraj Kumar 提问时间:11/2/2023 最后编辑:ddaNeeraj Kumar 更新时间:11/3/2023 访问量:94
在 Python 中使用 JavaScript 中的 crypto.subtle 解密由 AES-CBC 加密的字符串
Decrypt a string in Python that was encrypted by AES-CBC using crypto.subtle in JavaScript
问:
我正在处理一种情况,我需要通过AES-CBC算法使用JavaScript在客户端加密有效负载,但后来使用Python在后端对其进行解密。JavaScript 中用于加密的模块是 crypto.subtle,并且大多数参数都以字节为单位。
在 python2 中,我使用一个名为 PyCrypto 的模块,其中参数主要在字符串中。这种差异导致解密问题,我得到的输出与加密的输出不同。请帮我找到我做错了什么。这是我正在使用的代码:
加密 (JavaScript)
async function encrypt(content, key) {
var byteKey = new TextEncoder().encode(key);
var byteContent = new TextEncoder().encode(content);
// Generate an AES key using the Crypto API
var AESKey = await crypto.subtle.importKey("raw", byteKey, "AES-CBC", false, ["encrypt"]);
// Encrypt using AES algorithm
var encryptedBytes = await crypto.subtle.encrypt(
{ name: "AES-CBC", iv: new Uint8Array(16) }, AESKey, byteContent);
// Convert the encrypted byte array to a Base64 string
var encryptedBase64 = btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedBytes)));
// Return the encrypted string
return encryptedBase64;
}
例:
encrypt("A sample string", "samplekey1234567").then(res => console.log(res))
OUTPUT: YZGjFFgnngBBBTSm8euZEw==
解密 (Python)
from Crypto.Cipher import AES
def decrypt(content, key):
cipher = AES.new(key, AES.MODE_CBC, buffer(bytearray(16), 0,16))
return cipher.decrypt(content)
例:
cipher = AES.new("samplekey1234567", AES.MODE_CBC, buffer(bytearray(16), 0,16))
cipher.decrypt("YZGjFFgnngBBBTSm8euZEw==".decode("ascii")) # Gives ValueError: Input strings must be a multiple of 16 in length (Why is this not an issue in JavaScript equivalent?)
cipher.decrypt("YZGjFFgnngBBBTSm8euZEw== ".decode("ascii"))
OUTPUT: 'H\x15\xeeMZ\xbd\xdaX\xe6U\xe27F\x9a\xb4e' # Not the original string
答:
这里出了点问题:你在两边都使用看似随机的静脉注射,而且很可能不一样......AES-CBC 需要密钥和已知的 IV 才能工作。您需要将密码和 IV 传递给 Python 代码——它已经知道密钥。没有它,你就是 SOL。所以你的首要任务是产生一个随机的 IV(永远不要重复使用相同的 IV),而不仅仅是使用 ...在调用之前,make 一个 ,并用一些东西填充它,希望足够随机。是的,您需要将 IV 与密码一起传递给服务器。iv: new Uint8Array(16)
crypto.subtle.encrypt
Uint8Array(16)
cipher.decrypt("YZGjFFgnngBBBTSm8euZEw== ".decode("ascii"))
此外,另一个无济于事的问题是您正在尝试解密用空格填充的 Base64。哈哈不。将 Base64 内容(没有多余的空格)转回字节流(确保 binascii 没有在末尾添加虚假),然后解密 THAT。"YZGjFFgnngBBBTSm8euZEw=="
\n
>>> cipher = AES.new(b"samplekey1234567", AES.MODE_CBC, bytearray(16))
>>> cipher.decrypt(binascii.a2b_base64((b"YZGjFFgnngBBBTSm8euZEw==").decode("ascii")))
b'A sample string\x01'
[在这种情况下,由于您在两端都使用了空缓冲区,即 16 个零,我可以重现您的示例并解密。但是,正如我所说,不要使用和传递非随机 IV,也不要两次相同的 IV]。
我正在使用 Python3 – 你也应该如此。所以我用字符串代替,但概念保持不变。最后一个字节 , 是填充。由于 AES 对 16 个字节的块进行编码,因此它将在块末尾添加剩余的“空”字符数,使其为 16 个字节。在本例中,“A sample string”为 15 个字节,因此它添加了 .您可能希望对字符串终止符进行编码,以便 Python 知道字符串停止的位置...bytes
\x01
0x01
0x00
评论