我正在尝试使用 Crypto.js
使用其 AES
算法在 Node 中生成加密文本。它在 Js 中可以用于加密和解密。同样,我尝试使用 pycrypto 在 Python 中实现相同的功能,它在 python 中进行加密和解密。但是当我想使用JS中的加密密文在Python中解密时,问题就出现了。问题是JS生成的密文和Python生成的密文不一样。
这是基于 JS 的 AES 用法:
import CryptoJS from "crypto-js";
let str = "lol";
let salt = "ABCDEFGHIJKLMNOP";
let key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP";
salt = CryptoJS.enc.Hex.parse(salt);
key = CryptoJS.enc.Hex.parse(key);
const options = {
iv: salt,
padding: CryptoJS.pad.ZeroPadding,
mode: CryptoJS.mode.CFB,
};
// function to encrypt the string
function encrypt(str, salt, key) {
const cipher = CryptoJS.AES.encrypt(str, key, options);
console.log("cipher", CryptoJS.enc.Hex.stringify(cipher.ciphertext));
return cipher.ciphertext.toString(CryptoJS.enc.Base64);
}
// function to decrypt the string
function decrypt(str, salt, key) {
const cipher = CryptoJS.AES.decrypt(str, key, options);
return cipher.toString(CryptoJS.enc.Utf8);
}
const encrypted = encrypt(str, salt, key);
console.log("encrypted", encrypted);
const decrypted = decrypt(encrypted, salt, key);
console.log("decrypted", decrypted);
// OUTPUT
// encrypted sd4Xpz/ws8x2j+cgF17t6A==
// decrypted lol
这是基于 Python 的 AES 用法:
from Crypto.Cipher import AES
from base64 import b64encode, b64decode
str = "lol";
salt = b"ABCDEFGHIJKLMNOP";
key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP";
enc_dec_method = 'utf-8'
def encrypt(str_to_enc, str_key, salt):
aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt)
hx_enc = aes_obj.encrypt(str_to_enc.encode('utf8'))
df = b64encode(hx_enc)
mret = b64encode(hx_enc).decode(enc_dec_method)
return mret
def decrypt(str_to_dec, str_key, salt):
aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt)
str_tmp = b64decode(str_to_dec.encode(enc_dec_method))
str_dec = aes_obj.decrypt(str_tmp)
mret = str_dec.decode(enc_dec_method)
return mret
test_enc_text = encrypt(str, key, salt)
test_dec_text = decrypt(test_enc_text, key, salt)
print(f"Encrypted Text: {test_enc_text}")
print(f"Decrypted Text: {test_dec_text}")
# OUTPUT
# Encrypted Text: o9XB
# Decrypted Text: lol
- 我厌倦了用这两种语言进行加密和解密,并检查了这两个库的文档和源代码。
- 也尝试检查我是否缺少编码或解码,但没有成功。
我在这里遗漏了哪些关键概念可以帮助弥合此处的兼容性差距?
最佳答案
这些代码不兼容,因为:
Key 和 IV 不是十六进制编码,因此十六进制编码器不得在 CryptoJS 代码中使用。如果要像Python代码一样应用Utf-8编码,则必须使用Utf-8编码器。
salt = CryptoJS.enc.Utf8.parse(salt); key = CryptoJS.enc.Utf8.parse(key);
CFB 是一种不需要填充的流密码模式。但是,在当前的 CryptoJS 代码中,使用零填充 (
CryptoJS.pad.ZeroPadding
)。相反,必须禁用填充(这不会隐式发生,与 Python 代码不同):padding: CryptoJS.pad.NoPadding,
CFB 配置了一个附加参数,即段大小,它指定每个加密步骤加密的位数。 CryptoJS 代码仅支持一种段大小,即 128 位。使用 PyCryptodome 可以配置段大小,默认使用 8 位。为了兼容性,必须将其更改为 128 位:
aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt, segment_size=128)
通过这些更改,两个代码都是兼容的。
测试:两个代码都为以下明文提供以下密文:
plaintext: The quick brown fox jumps over the lazy dog
ciphertext: m0T/7e04eV49RTcgd7KtwHxSOavNzHNwlrvjt1YmmHidBy4rHS0oovclKQ==
请注意,您所说的盐实际上是初始化向量 (IV)。术语“盐”更常用于 key 导出函数(如 PBKDF2)。
关于安全性:用于测试的 salt 和 IV 的值是可以的,但在现实场景中,必须为每次加密的 IV 应用随机字节序列,该随机字节序列必须与密文一起传递到解密端(通常串联)。
此外,作为 key ,不必使用密码,而是使用随机字节序列。密码(当然是强密码)只能与 key 派生函数结合使用。
关于用Crypto.js和pycrypto加密生成不同的加密密文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75252906/