javascriptcryptographycryptojs

Converting crypto to crypto-js script (AES-256-CBC)


I have working encrypt()/decrypt() functions using Node.js native crypto lib and they works fine

const crypto = require('crypto');


const ENC_KEY = "bf37b0999c7717c17b2c1d90470cb41e";

function encrypt(data, key, ivLength = 16) {
  const iv = crypto.randomBytes(ivLength);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  let encrypted = cipher.update(data, 'utf8', 'base64');
  encrypted += cipher.final('base64');

  const resultData = {
    'iv': iv.toString('base64'),
    'data': encrypted
  }
  const response = btoa(JSON.stringify(resultData))
  return response;
};

function decrypt(data, key) {
  const jsonData = JSON.parse(Buffer.from(data, 'base64').toString('ascii'));
  const iv = Buffer.from(jsonData['iv'], 'base64')
  
  let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  let decrypted = decipher.update(jsonData['data'], 'base64', 'utf8');
  const result = (decrypted + decipher.final('utf8'));
  return result;
};


const phrase = "ORIGINAL PHRASE";

const encryptedCrypto = encrypt(phrase, ENC_KEY);
const decryptedCrypto = decrypt(encryptedCrypto, ENC_KEY);
console.log(`Decoded string: ${decryptedCrypto}`);

I need to rewrite encrypt() function with crypto-js lib so the original decrypt() function work with it. I can't modify anything except encrypt() function.

I've tried but I didn't succeed. Could someone help me with that?

function encrypt(data, key, ivLength = 16) {
  const iv = CryptoJS.lib.WordArray.random(ivLength);
  const encrypted = CryptoJS.AES.encrypt(data, CryptoJS.enc.Hex.parse(key), {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.NoPadding
  });

  const resultData = {
    'iv': CryptoJS.enc.Hex.parse(iv).toString('base64'),
    'data': encrypted
  }
  const result = btoa(JSON.stringify(resultData))
  return result;
}

Solution

  • Your crypto-js code is close, but has some flaws

    This is tested working code for the encrypt function

    function encrypt(data, key, ivLength = 16) {
        const iv = CryptoJS.lib.WordArray.random(ivLength);
        const encrypted = CryptoJS.AES.encrypt(
            data,
            CryptoJS.enc.Utf8.parse(key),
            {
                iv: iv,
                mode: CryptoJS.mode.CBC,
                //padding: CryptoJS.pad.NoPadding,
            }
        );
        const resultData = {
            iv: CryptoJS.enc.Base64.stringify(iv),
            data: CryptoJS.enc.Base64.stringify(encrypted.ciphertext),
        };
        const result = btoa(JSON.stringify(resultData));
        return result;
    }
    

    Note CryptoJS.enc.Utf8.parse(key) not CryptoJS.enc.Hex.parse(key)

    If the key as shown (32 characters) were converted using .Hex.parse it would end up 128 bit, not 256 bit.

    Removed padding: CryptoJS.pad.NoPadding, since that will break the decryption

    Use CryptoJS.enc.Base64.stringify in resultData since that's basically what you are doing in the node version

    Note: crypto-js development is discontinued - you should be using native crypto in node and browser i.e. crypto.subtle

    The main challenge is the asynchronous nature of crypto.subtle