Decoding Symmetric Cyphers with Crypto-JS

June 8, 2016 | 2 min Read

Symmetric cryptographic algorithms are algorithms that use the same key for both encryption and decryption. That is, a Code + Key will produce a Cypher, and the Cypher + Key will produce the Code.

Crypto-JS is a popular cryptography library which supports a number of different cryptographic algorithms including Advanced Encryption Standard (AES). Encrypting and decrypting using AES with Crypto-JS is straightforward:

var CryptoJS = require("crypto-js");
 
// Encrypt 
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123');
 
// Decrypt 
var bytes  = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123');
var plaintext = bytes.toString(CryptoJS.enc.Utf8);
 
console.log(plaintext);

However, what happens when a different Cypher or Key is used (for example, if someone enters the wrong password)? Hopefully the Code is not returned, but what is? I wrote a small script that decrypted 100,000 random cyphers using 100,000 random keys. The results were interesting:

  • 97% of the time Crypto-JS returns the empty string
  • 0.05% of the time some other string is returned

But what about the remaining 2.5%? Turns out that about 2.5% of the time Crypto-JS returns a sequence of bytes that could not be converted to a UTF-8 character sequence. In this case the error: Error: Malformed UTF-8 data was thrown.

If you are using Crypto-JS, and you cannot verify the Cypher or the Key (which is probably good practice), then make sure you handle byte sequences that cannot be converted to UTF-8 strings, or convert the results to UTF-16 strings. That is, don’t assume that what you decipher can always be converted to UTF-8. Now my Crypto-JS code looks like this:

var CryptoJS = require("crypto-js");
 
// Encrypt 
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123');
 
// Decrypt 
var bytes  = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123');
try {
  var plaintext = bytes.toString(CryptoJS.enc.Utf8);
} catch (e) {
  var plaintext = "";
}
 
console.log(plaintext);

The code I used for this test is available on GitHub.

Stay Updated with Our Latest Articles

Want to ensure you get notifications for all our new blog posts? Follow us on LinkedIn and turn on notifications:

  1. Go to the EclipseSource LinkedIn page and click "Follow"
  2. Click the bell icon in the top right corner of our page
  3. Select "All posts" instead of the default setting
Follow EclipseSource on LinkedIn
Ian Bull

Ian Bull

Ian is an Eclipse committer and EclipseSource Distinguished Engineer with a passion for developer productivity.

He leads the J2V8 project and has served on several …