在浏览器中使用Node和CryptoJS之间的AES加密时的问题

时间:2021-12-23 18:25:02

I want encrypt a string with Node, and decrypt the string with CryptoJS in browser.

我想用Node加密一个字符串,并在浏览器中用CryptoJS解密字符串。

Encrypt:

加密:

var crypto = require('crypto');

function encrypt(txt, cryptkey) {
    var cipher = crypto.createCipher('aes-256-cbc', cryptkey);
    var crypted = cipher.update(txt, 'utf8', 'hex');
    crypted += cipher.final('hex');
    return crypted;
}

encrypt('1', 'key'); // 83684beb6c8cf063caf45cb7fad04a50

Include:

包括:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>

Decrypt:

解密:

var decrypted = CryptoJS.AES.decrypt('83684beb6c8cf063caf45cb7fad04a50', 'key');
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // empty string

The actual result is empty string.

实际结果是空字符串。

What is the right way to decrypt data from node?

从节点解密数据的正确方法是什么?

1 个解决方案

#1


3  

CryptoJS supports the same password-based encryption mode that the crypto module in node.js supports which is implemented as the equivalent to EVP_BytesToKey. CryptoJS generates a random salt by default, but node.js doesn't and uses an empty salt. An empty salt is bad and should not be used. Also, it's not secure to derive a key from a password with this method. One needs to use PBKDF2 (supported by CryptoJS and node.js) or similar with a lot of iterations and a random salt.

CryptoJS支持与node.js中的crypto模块支持的相同的基于密码的加密模式,该模式实现为等同于EVP_BytesToKey。 CryptoJS默认生成随机盐,但node.js不生成并使用空盐。空盐是坏的,不应该使用。此外,使用此方法从密码派生密钥也不安全。需要使用PBKDF2(由CryptoJS和node.js支持)或类似的迭代和随机盐。

var ctHex = '83684beb6c8cf063caf45cb7fad04a50';
var ct = CryptoJS.enc.Hex.parse(ctHex);
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var decrypted = CryptoJS.AES.decrypt({ciphertext: ct, salt: salt}, 'key');

document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "1"<br/>Got: "<span id="dec"></span>"


You said that this will be done over HTTP.

你说这将通过HTTP完成。

If you want to use transport security without user intervention, then this is completely insecure, because the key needs to be transmitted alongside of the ciphertext which makes this at best obfuscation.

如果你想在没有用户干预的情况下使用传输安全性,那么这是完全不安全的,因为密钥需要与密文一起传输,这使得这最好是混淆。

If the user and the server both know the password before communication, then this is still insufficient, because the key derivation that both CryptoJS and node.js provide is insufficient and something like PBKDF2 must be used. MD5 is easily brute-forceable.

如果用户和服务器在通信之前都知道密码,那么这仍然是不够的,因为CryptoJS和node.js提供的密钥派生是不够的,必须使用类似PBKDF2的密钥。 MD5很容易暴力破解。

You would need to use asymmetric cryptography to protect this communication against a passive attacker (one that cannot inject arbitrary packets into the stream between server and client). I suggest that you generate an RSA key pair and sent the public key to the client so that the client can encrypt a message to the server. You can use forge for that.

您需要使用非对称加密来保护此通信免受被动攻击者(无法将任意数据包注入服务器和客户端之间的流)。我建议您生成RSA密钥对并将公钥发送到客户端,以便客户端可以加密到服务器的消息。你可以使用锻造。


Encryption would look like this:

加密看起来像这样:

var salt = CryptoJS.lib.WordArray.create(0); // empty array
var params = CryptoJS.kdf.OpenSSL.execute('key', 256/32, 128/32, salt);
var pt = '1';
var encrypted = CryptoJS.AES.encrypt(pt, params.key, {iv: params.iv});

document.querySelector("#enc").innerHTML = encrypted.ciphertext.toString();
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "83684beb6c8cf063caf45cb7fad04a50"<br/>Got: "<span id="enc"></span>"

#1


3  

CryptoJS supports the same password-based encryption mode that the crypto module in node.js supports which is implemented as the equivalent to EVP_BytesToKey. CryptoJS generates a random salt by default, but node.js doesn't and uses an empty salt. An empty salt is bad and should not be used. Also, it's not secure to derive a key from a password with this method. One needs to use PBKDF2 (supported by CryptoJS and node.js) or similar with a lot of iterations and a random salt.

CryptoJS支持与node.js中的crypto模块支持的相同的基于密码的加密模式,该模式实现为等同于EVP_BytesToKey。 CryptoJS默认生成随机盐,但node.js不生成并使用空盐。空盐是坏的,不应该使用。此外,使用此方法从密码派生密钥也不安全。需要使用PBKDF2(由CryptoJS和node.js支持)或类似的迭代和随机盐。

var ctHex = '83684beb6c8cf063caf45cb7fad04a50';
var ct = CryptoJS.enc.Hex.parse(ctHex);
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var decrypted = CryptoJS.AES.decrypt({ciphertext: ct, salt: salt}, 'key');

document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "1"<br/>Got: "<span id="dec"></span>"


You said that this will be done over HTTP.

你说这将通过HTTP完成。

If you want to use transport security without user intervention, then this is completely insecure, because the key needs to be transmitted alongside of the ciphertext which makes this at best obfuscation.

如果你想在没有用户干预的情况下使用传输安全性,那么这是完全不安全的,因为密钥需要与密文一起传输,这使得这最好是混淆。

If the user and the server both know the password before communication, then this is still insufficient, because the key derivation that both CryptoJS and node.js provide is insufficient and something like PBKDF2 must be used. MD5 is easily brute-forceable.

如果用户和服务器在通信之前都知道密码,那么这仍然是不够的,因为CryptoJS和node.js提供的密钥派生是不够的,必须使用类似PBKDF2的密钥。 MD5很容易暴力破解。

You would need to use asymmetric cryptography to protect this communication against a passive attacker (one that cannot inject arbitrary packets into the stream between server and client). I suggest that you generate an RSA key pair and sent the public key to the client so that the client can encrypt a message to the server. You can use forge for that.

您需要使用非对称加密来保护此通信免受被动攻击者(无法将任意数据包注入服务器和客户端之间的流)。我建议您生成RSA密钥对并将公钥发送到客户端,以便客户端可以加密到服务器的消息。你可以使用锻造。


Encryption would look like this:

加密看起来像这样:

var salt = CryptoJS.lib.WordArray.create(0); // empty array
var params = CryptoJS.kdf.OpenSSL.execute('key', 256/32, 128/32, salt);
var pt = '1';
var encrypted = CryptoJS.AES.encrypt(pt, params.key, {iv: params.iv});

document.querySelector("#enc").innerHTML = encrypted.ciphertext.toString();
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "83684beb6c8cf063caf45cb7fad04a50"<br/>Got: "<span id="enc"></span>"