将节点密码AES-256-CBC转换为CryptoJS

2022-08-05 00:00:00 node.js aes javascript cryptojs node-crypto

如何将以下节点内置的crypto module encryption转换为CryptoJS?

const crypto = require('crypto');

const pass = 'some,password:)with>spec(chars*'
const cipher1 = crypto.createCipher('aes-256-cbc', pass)
const c1 = cipher1.update(input, 'utf8', 'hex') + cipher1.final('hex')

我尝试了类似的方法,但结果不同:

const CryptoJS = require('crypto-js');

const pass = 'some,password:)with>spec(chars*'
const cipher2 = CryptoJS.AES.encrypt(input, pass, {
    mode: CryptoJS.mode.CBC,
});
const c2 = cipher2.ciphertext.toString(CryptoJS.enc.Hex);

我需要将此脚本用作邮递员先决条件脚本,因为它不支持节点的crypto,但crypto-js


解决方案

这两个代码都使用openssl专有密钥派生函数EVP_BytesToKey(),迭代次数为1,摘要为md5。
NodeJS不使用盐,而CryptoJS应用随机盐。因此,每次加密时,NodeJS结果不变,而CryptoJS结果总是变化(假设相同的明文和密码)。

因此,要获得NodeJS代码和CryptoJS代码的结果,您不能使用SALT。但是,默认情况下,始终应用盐。这只能通过使用密钥派生函数EvpKDF显式确定KEY和IV,然后在加密中使用两者来避免:

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
var input = "The quick brown fox jumps over the lazy dog";
var pass = 'some,password:)with>spec(chars*'

var keySize = 32/4;
var ivSize = 16/4;
var kdf = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize, hasher: CryptoJS.algo.MD5 }).compute(pass, ''); // no salt!
var key = CryptoJS.lib.WordArray.create(kdf.words.slice(0, keySize), keySize * 4);
var iv = CryptoJS.lib.WordArray.create(kdf.words.slice(keySize), ivSize * 4);
var ciphertextCP = CryptoJS.AES.encrypt(input, key, {iv: iv}); // default: CBC, PKCS#7 padding
var ciphertext = ciphertextCP.ciphertext.toString(CryptoJS.enc.Hex);
document.getElementById("ct").innerHTML = ciphertext; // d98cf2d285bf0c1d796226190bf54d9c5540300ee1c6f35618f8bb3564b5053920ec958d31b41bbe4e4880e23543d709
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="ct"></p>

此CryptoJS代码为与NodeJS代码相同的明文和密码生成相同的密文。


请注意,使用EVP_BytesToKey()和所选参数的密钥派生如今已被弃用,并被认为是不安全的。与CryptoJS相比,NodeJS在更大程度上是如此,因为缺少盐。

避免内置密钥派生函数,直接指定密钥更安全。
为此,在NodeJS中使用createCipheriv(),并在CryptoJS代码中将密钥作为WordArray传递。这样,必须为每次加密显式生成随机IV。
或者,可以使用可靠的密钥派生函数,如PBKDF2,这两个库都支持该函数。

相关文章