RobbB
RobbB

Reputation: 1354

How to properly encode strings so to decrypt with CryptoJs in NodeJS?

I am working out a custom hybrid encryption system. I've got symmetric encryption & asymmetric encryption & decryption all handled server-side. All I need to work out now is symmetric decryption.

I got some trouble because my client is sending symmetric key, iv & data all in string format (after asymmetric decryption), but CryptoJS is very touchy with it's encoding. It's also very confusing and vague as far as documentation goes- at least for a relatively new developer. I just can't figure out what encoding CryptoJS wants for each argument. I figure I should have guessed right by now, but no.

Docs
Some help I've gotten previously

I'm requesting help getting the encoding right so that I can decrypt with the following. And thanks a lot for any assistance.

Example of data after asymmetric decryption as per below (throw away keys):

symmetricKey: bDKJVr5wFtQZaPrs4ZoMkP2RjtaYpXo5HHKbzrNELs8=,
symmetricNonce: Z8q66bFkbEqQiVbrUrts+A==,
dataToReceive: "hX/BFO7b+6eYV1zt3+hu3o5g61PFB4V3myyU8tI3W7I="
exports.transportSecurityDecryption = async function mmTransportSecurityDecryption(dataToReceive, keys) {
  const JSEncrypt = require('node-jsencrypt');
  const CryptoJS = require("crypto-js");

  // Asymmetrically decrypt symmetric cypher data with server private key
  const privateKeyQuery = new Parse.Query("ServerPrivateKey");
  const keyQueryResult = await privateKeyQuery.find({useMasterKey: true});
  const object = keyQueryResult[0];
  const serverPrivateKey = object.get("key");
  const crypt = new JSEncrypt();
  crypt.setPrivateKey(serverPrivateKey);
  let decryptedDataString = crypt.decrypt(keys);
  let decryptedData = JSON.parse(decryptedDataString);

  // Symmetrically decrypt transit data
  let symmetricKey = decryptedData.symmetricKey;
  let symmetricNonce = decryptedData.symmetricNonce;
                                                        // Works perfectly till here <---
  var decrypted = CryptoJS.AES.decrypt(
    CryptoJS.enc.Hex.parse(dataToReceive),
    CryptoJS.enc.Utf8.parse(symmetricKey),
    {iv: CryptoJS.enc.Hex.parse(symmetricNonce)}
    );
  return decrypted.toString(CryptoJS.enc.Utf8);
}

Upvotes: 2

Views: 2591

Answers (1)

Topaco
Topaco

Reputation: 49296

  • You are using the wrong encoders for data, key and IV. All three are Base64 encoded (and not hex or Utf8). So apply the Base64 encoder.
  • The ciphertext must be passed to CryptoJS.AES.decrypt() as a CipherParams object or alternatively Base64 encoded, which is implicitly converted to a CipherParams object.

When both are fixed, the plain text is: "[\"001\",\"001\"]".

var symmetricKey =  "bDKJVr5wFtQZaPrs4ZoMkP2RjtaYpXo5HHKbzrNELs8="
var symmetricNonce = "Z8q66bFkbEqQiVbrUrts+A=="
var dataToReceive = "hX/BFO7b+6eYV1zt3+hu3o5g61PFB4V3myyU8tI3W7I="

var decrypted = CryptoJS.AES.decrypt(
    dataToReceive, // pass Base64 encoded
    //{ciphertext: CryptoJS.enc.Base64.parse(dataToReceive)}, // pass as CipherParams object, works also
    CryptoJS.enc.Base64.parse(symmetricKey),
    {iv: CryptoJS.enc.Base64.parse(symmetricNonce)}
);

console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

Upvotes: 1

Related Questions