hong developer
hong developer

Reputation: 13906

Why did node.js use Crypto.js to encrypt, but fails to decrypt?

I used json to encrypt the values. However, I tried to decrypt the value again, but it was unsuccessful. The value is empty.

node.js source

import CryptoJS from 'crypto-js';

const EncryptHex = (string, chip) => {
  let result = '';
  try {
    const key = CryptoJS.enc.Hex.parse(STORE_KEY);
    if (chip === 'AES') {
      const iv = CryptoJS.lib.WordArray.create([0x00, 0x00, 0x00, 0x00]);
      result = CryptoJS.AES.encrypt(string, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
      });
      result = result.ciphertext.toString(CryptoJS.enc.Hex);
      DecryptHex(result, 'AES', STORE_KEY);
    } else {
      result = CryptoJS.HmacSHA256(string, key).toString(CryptoJS.enc.Hex);
    }
    return result;
  } catch (error) {
    throw error;
  }
};

const DecryptHex = (string, chip, skey) => {
  let result = '';
  const key = CryptoJS.enc.Hex.parse(skey);
  const iv = CryptoJS.lib.WordArray.create([0x00, 0x00, 0x00, 0x00]);
  try {
    const array = CryptoJS.enc.Hex.parse(string);
    if (chip === 'AES') {
      result = CryptoJS.AES.decrypt(array, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
      }).toString();
      console.log('$$$$');
      console.log('result : ', result);
      console.log('$$$$');
    } else {
      result = array;
    }
    return result;
  } catch (error) {
    throw error;
  }
};

log value

$$$$
result :  
$$$$

What is the reason? How can I solve this problem?

Upvotes: 1

Views: 935

Answers (2)

Topaco
Topaco

Reputation: 49141

CryptoJS.AES.decrypt expects as ciphertext either a Base64 encoded string (which is implicitly converted into a CipherParams object) or a CipherParams object (see here).

  • Option 1 - The quick way: The ciphertext can be Base64 encoded in DecryptHex e.g. with:

    const array = CryptoJS.enc.Hex.parse(string).toString(CryptoJS.enc.Base64);
    

    Alternatively EncryptHex could also use a Base64 instead of a hex encoding.

  • Option 2 - The tidier way: The detour via Base64 encoding can be avoided by passing the ciphertext directly as CipherParams object in CryptoJS.AES.decrypt. To do this, simply replace array with { ciphertext: array } in CryptoJS.AES.decrypt:

    const array = CryptoJS.enc.Hex.parse(string); 
    result = CryptoJS.AES.decrypt({ ciphertext: array }, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
    }).toString(); 
    

Note also that CryptoJS.AES.decrypt returns the decrypted data as a WordArray (see here), which is currently hex encoded with toString(). With toString(CryptoJS.enc.Utf8) the result is Utf8 decoded.

Upvotes: 2

Terry Lennox
Terry Lennox

Reputation: 30675

There are a couple of things we need to do, number 1, get the right key length, this should be either 128,192, or 256 bits long.

In this code I'm using a 256 bit key. Don't use this in production :)

Also, if you use the format: CryptoJS.format.Hex when decrypting, it will accept a hex encoded ciphertext.

This should encrypt and then decrypt a test message:

// Using a 256-bit key to ensure we use AES-256
STORE_KEY = "7246b9b8171743cd9cf285367a2fd5ad";

const EncryptHex = (string, chip, skey) => {
    let result = '';
    try {
        const key = CryptoJS.enc.Hex.parse(skey);
        if (chip === 'AES') {
            const iv = CryptoJS.lib.WordArray.create([0x00, 0x00, 0x00, 0x00]);
            result = CryptoJS.AES.encrypt(string, key, {
                iv: iv,
                mode: CryptoJS.mode.CBC,
            });
            result = result.ciphertext.toString(CryptoJS.enc.Hex);
        } else {
            result = CryptoJS.HmacSHA256(string, key).toString(CryptoJS.enc.Hex);
        }
        return result;
    } catch (error) {
        throw error;
    }
};

const DecryptHex = (encryptedStringHex, chip, skey) => {
    let result = '';
    const key = CryptoJS.enc.Hex.parse(skey);
    const iv = CryptoJS.lib.WordArray.create([0x00, 0x00, 0x00, 0x00]);
    try {
        const array = CryptoJS.enc.Hex.parse(encryptedStringHex);
        if (chip === 'AES') {
            result = CryptoJS.AES.decrypt(encryptedStringHex, key, {
                iv: iv,
                format: CryptoJS.format.Hex,
                mode: CryptoJS.mode.CBC,
            }).toString(CryptoJS.enc.Utf8);
            console.log('$$$$');
            console.log('result : ', result);
            console.log('$$$$');
        } else {
            result = array;
        }
        return result;
    } catch (error) {
        throw error;
    }
};

let encrypted = EncryptHex("A good story cannot be devised; it has to be distilled", "AES", STORE_KEY);
console.log("Encrypted data:", encrypted);

console.log("Decrypted data:");
DecryptHex(encrypted, "AES", STORE_KEY);

Upvotes: 2

Related Questions