Decoding Symmetric Cyphers with Crypto-JS

Decoding Symmetric Cyphers with Crypto-JS

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:

<pre lang="javascript">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);
</pre>

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:

<pre lang="javascript">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);
</pre>

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

Ian Bull

Ian is an Eclipse committer and EclipseSource Distinguished Engineer with a passion for developer producitivy. He leads the J2V8 project and has served on serveral Eclipse technical committies. Ian holds a Bachelor and Master's degree from the University of Waterloo and a PhD from the University of Victoria.
Keine Kommentare vorhanden

Es tut uns leid, es sind zurzeit keine Kommentare möglich.