Search code examples
node.jsencryptionaescryptojs

CrytoJS AES: Encrypted string gets decrypted to empty string


I was tinkering with crypto-js and AES.

I have a seemingly straightforward piece of code which takes a plainText and encrypts it using AES with a key and an initial vector.

When I try to decrypt the encrypted text, it gets decrypted to empty string for some reason.

This is the snippet:

const { enc, AES } = require("crypto-js");

const KEY = enc.Utf8.parse("this is a key");
const IV = enc.Utf8.parse("this is initial vector");

const originalText = "someone@example.com";

const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();

console.log(`"${originalText}" was encrypted to "${hashText}"`);

const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);

console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);

The output I get is:

"someone@example.com" was encrypted to "IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA="
"IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA=" was decrypted to ""

Can someone explain what is going on? I have seen quite a few examples of it over the Internet and they all seem to working just fine. But here, the text is not getting decrypted.

PS: The version I am using is "crypto-js": "^3.1.9-1",


Solution

  • Maybe try changing your code ever so slightly, this works for me.

    As stated in the comments, I believe the problem with your initial example was the key length.

    const { enc, AES } = require("crypto-js");
    
    // Keep as a string..
    const KEY = "this is a key";
    const IV = enc.Utf8.parse("this is initial vector");
    
    const originalText = "someone@example.com";
    
    const hash = AES.encrypt(originalText, KEY, { iv: IV });
    const hashText = hash.toString();
    
    console.log(`"${originalText}" was encrypted to "${hashText}"`);
    
    const hashTextCopy = `${hashText}`;
    const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
    const decryptText = decrypt.toString(enc.Utf8);
    
    console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
    

    This also works:

    const { enc, AES } = require("crypto-js");
    
    // 128-bit key works nicely
    const KEY = enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
    const IV = enc.Utf8.parse("this is initial vector");
    
    const originalText = "someone@example.com";
    
    const hash = AES.encrypt(originalText, KEY, { iv: IV });
    const hashText = hash.toString();
    
    console.log(`"${originalText}" was encrypted to "${hashText}"`);
    
    const hashTextCopy = `${hashText}`;
    const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
    const decryptText = decrypt.toString(enc.Utf8);
    
    console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
    

    The key:

    const KEY = enc.Utf8.parse("abcdfghi");
    

    Will also work correctly (since it's 128-bits). 256 would work too.

    const KEY = enc.Utf8.parse("abcdfghijklmnopq");
    

    If you just use a pass phrase, a 256-bit key will be generated from it.