javascript - Problems when using AES crypto between Node and CryptoJS in browser - Stack Overflow

admin2025-04-20  0

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=".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?

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./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?

Share Improve this question edited Nov 26, 2015 at 11:29 green13 asked Nov 26, 2015 at 10:23 green13green13 31 silver badge4 bronze badges 7
  • Are you sure symmetric encryption is the way to go? The encryption key is visible to the browser, therefore anyone running your JS can obtain the key and that makes the whole point of encrypting redundant. – Mjh Commented Nov 26, 2015 at 11:35
  • The encryption key is different for each user agent. This solution is for encryption of data transferred over http. – green13 Commented Nov 26, 2015 at 12:03
  • @green13 You cannot secure munication with symmetric encryption if you send it over HTTP, because you would have to send the key along with it and it would be plainly visible. This would be obfuscation at best. You could introduce asymmetric (actually hybrid) encryption like RSA+AES or ECIES, but this is only secure against passive attackers. Just use HTTPS and you will be fine. For reference: Javascript Cryptography Considered Harmful – Artjom B. Commented Nov 26, 2015 at 14:10
  • What @ArtjomB. said - you should use https. It doesn't matter if the key is different for every agent. You have to deliver that key to the js code, and people using the web app can see the key. Better approach is to share the public key and keep the private key on server. You can do so with self-generated keypair, crypto.js can generate a keypair but you'd just be doing what SSL does anyway - the easiest way for you is to use https. – Mjh Commented Nov 26, 2015 at 14:42
  • @Mjh CryptoJS doesn't support asymmetric crypto, but forge does which can also run in node.js. – Artjom B. Commented Nov 26, 2015 at 14:45
 |  Show 2 more ments

1 Answer 1

Reset to default 7

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./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 pletely 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 munication, 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 munication 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./CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "83684beb6c8cf063caf45cb7fad04a50"<br/>Got: "<span id="enc"></span>"

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745158363a287993.html

最新回复(0)