[Updated October 16th 2012 with corrected information from CryptoJS author Jeff Mott - look for the UPDATED tag below]
The Google Code Crypto-JS page titles “JavaScript implementations of standard and secure cryptographic algorithms” and that’s exactly what it’s all about. I strongly suggest you to read the QuickStart Guide: this CryptoJS Tutorial for Dummies is just made with comments in the margin of it - underlining important stuff I didn’t notice when I first approached it. The official documentation is precise yet kind of succint - it makes sense to those who master the topic, but it may disorient the newcomers (like me when I get there for the first time). I’m just on my way learning both cryptography theory and this nice JS library, the following is only a collection of basic advices and personal notes. Please forgive me for using a very… non-specialized jargon.
Caveat: I use to write code in Extendscript - which is an Adobe made superset of Javascript adding nice extras, such as: file-system access, user interface development tools, external communication, preprocessing directives, XML integration, etc. I say so because it seems that my mindset is a bit shifted from the one of the pure Javascript developer (for instance, I’ve not to worry about privacy issues arising from readable code - my .jsx files are binary encrypted by default when I export them from the ESTK - ExtendScript ToolKit). I use to write Coffeescript, a nice smart language that compiles to Javascript, but I won’t us it here. Lot of extra resources on the Coffeescript language here.
Files
First, download the CryptoJS package (3.0.2 at the time of this post). It contains two folders:
- components - with both minified and commented JS files.
- rollups - minified files (one for each algorithm) bundled with core code.
Components files have dependencies: you have to link at least core.js, while rollups are quite self contained. In Extendscript, save a test.jsx file alongside (or within) the CryptoJS folder and set the preprocessing directives:
The #include (redundant here) are the equivalent of the following tag in HTML documents:
Be aware that you need to save the file at least once otherwise the include can’t resolve the path.
Word Array and Encodings
CryptoJS makes large use of Word Array - that is, arrays of 32-bits words (instances of the CryptoJS.lib.WordArray
); few useful functions:
Mind you, quoting the Guide: “When you use a WordArray object in a string context”, that is, an alert box or the Console, “it’s automatically converted to a hex string”. CryptoJS can manage different encodings, such as Base64, Hex, Latin1, UTF-8 and UTF-16. If you wonder how data would look like converted to them, paste this script in ESTK (Adobe’s ExtendScriptToolKit):
The output is as follows - I’ve used an Alert box because ESTK’s $.writeln() (as I suspect both console.log() and debug(), depending on the tool you use to run your JS code) can’t output but Hex and Base64:
Conversion Functions
Include both enc-base64-min.js
and enc-utf16-min.js
in your code. The functions are in the form:
Few examples as follows:
Hash Functions
So to speak, hashers are functions that take an input (no matter how large) and maps it to a fixed size, smaller one (the hash, or checksum). You can’t convert a hash back to the original input, yet you can check if the original data has been corrupted comparing the hashes. CryptoJS implements MD5, SHA-1 (used by Git) and its variant (2, 224, 384, 256 and 512).
The input "Message"
can either be a WordArray or a String (which will automatically be converted to the former, encoded UTF-8). Then you may:
Mind you the two forms are equivalent:
Ciphers
CryptoJS implements several Cipher Algorithms - in the following example AES:
The encryption results in a Base64 string, while the decrypted string is Hex. To get back the “Message” you need to:
If you run the encryption code several times, you’ll notice that the result will change:
yet each one of them will always decrypt to “Message”. How come?
Key, Salt and Initialization Vector
I’m not a cryptography expert - my raw understanding of the matter (after digging Wikipedia and StackOverflow) is as follows. Human memorizable passphrase are known to be bad ones. In order to make them more secure you can add a bunch of random bits (the salt) so that the actual key = function(Salt, Passphrase)
. An effect of Salt is that the same passphrase doesn’t always produce the same key. IV (initialization vector) is used, similarly, to ensure that the same plaintext (“Message”) doesn’t return the same ciphertext. It appears that Salt is used with passphrase to generate a key for encryption, then the resulting encryption is processed with IV. So to speak, the encryption = function(plaintext, passphrase, salt, IV)
. So when you write:
CryptoJS randomly generates for you what it need. [UPDATED] Alternatively, you can specify:
Input and output
The encrypt function takes a plaintext input as a String or WordArray (the “Message”), and either a similar passphrase or Hex Key and IV. [UPDATED] It’s important to reaffirm that, if you use a String as a passphrase, CryptoJS uses it to generate a random key and IV:
The code above is not proper, for two reasons:
- Key and IV are Strings, not Word Arrays!
- Consequently, the key is used as a String passphrase from which to derive a random actual key + IV pair - so they’re not the
key
andiv
variables you’ve declared.
When it comes to the output, things are a bit different because if you:
Actually, the encryption output is an object called CipherParams, and you can access its properties:
I’ve had some troubles understanding why they use this object as the vector of encrypted data - the pack of bits you and the other guy oversea securely swap. It looks like you’re putting your treasure map into a casket and ship it with the keys to open it (I would have used the ciphertext only). It puzzled me because you can successfully write:
[UPDATED]Â The explanation came directly from CryptoJS author Jeff Moss who wrote me:
Although the key is a property in the CipherParams object, the key is not included when that CipherParams object is serialized to a string. By default, CipherParams objects are serialized using a format from OpenSSL. Just do encrypted.toString(), and you can safely send that to the other side of the ocean.
So the alert(encrypted);
hex string you see in the last but one code block is definitely safe to use and share:
There’s definitely more to dig in this great CryptoJS library, I’m looking forward to explore it! This should be just enough to let you start implementing cryptography in your own projects.