Problems when using AES crypto between Node and CryptoJS in browser

我的未来我决定 提交于 2019-12-20 05:45:23

问题


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

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:


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.

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.

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.

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.


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>"


来源:https://stackoverflow.com/questions/33936092/problems-when-using-aes-crypto-between-node-and-cryptojs-in-browser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!