[Updated October 16th 2012 with corrected information from CryptoJS author Jeff Mott - look for the UPDATED tag below]
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:
enc-utf16-min.js in your code. The functions are in the form:
Few examples as follows:
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).
"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:
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
ivvariables 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.
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.