I tend to end up using the as3crypto library a lot. It offers a plethora of power, in the likeness of a massive metal robot smashing through thick mathematical problems; but the documentation assumes everyone is a cryptographer. I imagine an old man with a long beard in ancient Rome reading the as3crypto documentation on a scroll and double checking himself using a stick while writing in the sand.
On a recent fun project, I had to implement initialization vectors while using AES for the first time in as3crypto. An initialization vector is a string of data that is inserted into the cryptographic process to change the output each time you preform an operation. IV's can only be used in certain confidentiality modes as as3crypto calls them and block cipher modes as NIST calls them.
For this particular project, we were exchanging data between Flash and PHP using CBC mode. By default most examples online for AES in as3crypto do use IV's but they use the "simple" mode available in the library. Simple mode generates an IV for you and automatically adds it to the front of the data. For decryption the library attempts to peel off that beginning chunk of data and then re-apply it as the IV. Works fine if you are just doing encryption and decryption with as3crypto, but not so great if trying to play nice with other programming languages on the playground.
Enough of the explanation, lets look at how to do manual IV manipulation with AES 256 in CBC mode using as3crypto. I have seen many crypto tutorials that include bad information, so if you see it here, please leave a comment!
Understanding Input and Output Formats
For AES 256 in CBC mode, the expected IV size is 16 characters.
For AES 256 in CBC mode, the expected Key size is 32 characters (32 * 8 = 256..you follow?).
Padding for this example is PKCS5.
For Encryption:
Input is expected to be plain, normal human readable text.
The key is expected to be plain, normal human readable text.
The IV is expected to be in plain, normal human readable text.
Output IV is base64.
Output data is base64.
For Decryption:
Input is expected to be base 64 encoded.
The key is expected to be plain, normal human readable text.
The IV is expected to be base 64 encoded.
Decrypted output is plain, normal human readable text.
So here is the main entry point simple class:
package
{
import flash.display.Sprite;
public class as3crypto_AESCBC_IVExample extends Sprite
{
import com.technogumbo.crypto.AES_CBC_IV_Implementation;
public function as3crypto_AESCBC_IVExample()
{
/**
* If you have been tasked with crypto in AS3 then I am
* confident you do not need a UI to check this out.
*/
// Generated using https://www.grc.com/ppp.htm
// Limited to available hex characters 0123456789ABCDEF
var initialKey:String = "084B255737229811CF454AF2AE99B20E";
// Same thing here
var initialIV:String = "D8BF3DF78364B5CC";
// Data to Encrypt
var plainTextData:String = "Lets highlight some awesome non main stream video games. Suikoden 2(PS1), Vandal Hearts 1 and 2(PS1),"
+ "Brave Fencer Musashi(PS1), Nier(PS3), Stalker Series(PC)..thats enough for now.";
trace("Plain text before Encryption: " + plainTextData);
var results:Vector.<String> = AES_CBC_IV_Implementation.encrypt(plainTextData, initialKey, initialIV);
trace("Resulting B64 IV: " + results[0]);
trace("Resulting B64 Data: " + results[1]);
// ---- Now onto decryption ----
var endPlainTextData:String = AES_CBC_IV_Implementation.decrypt( results[1], initialKey, results[0]);
trace("Decrypted Plain Text: " + endPlainTextData );
trace("Live long and prosper fellow programmer.");
}
}
}
Now here is the little bit more complex crypto class.
package com.technogumbo.crypto
{
// Uses AS3Crypto
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.PKCS5;
import com.hurlant.util.Base64;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class AES_CBC_IV_Implementation
{
/**
* For Encryption:
Input is expected to be plain, normal human readable text.
The key is expected to be plain, normal human readable text.
The IV is expected to be in plain, normal human readable text.
Output data is base64. Why base64? Base64 is a form of encoding that can be sent over
the wire so to speak, so typically you see output and input of cryptographic operations
as b64 so it can travel across networks, between technologies.
Output IV is also base64.
If you are using an IV, it's common practice to send the IV along with the encrypted data.
*/
public static function encrypt(_InPlainData:String, _InPlainKey:String, _InPlainIV:String):Vector.<String> {
var kdata:ByteArray = Hex.toArray(Hex.fromString(_InPlainKey));
var data:ByteArray = Hex.toArray(Hex.fromString(_InPlainData));
var pad:IPad = new PKCS5;
// as3crypto determines the size based on the key. Look inside the Crypto class if you don't believe me.
var mode:ICipher = Crypto.getCipher("aes-cbc", kdata, pad);
var b64_IV:String = "";
if (mode is IVMode) {
var ivmode:IVMode = mode as IVMode;
// Just remember this is just a cast. The IV is still being set on the mode variable.
ivmode.IV = Hex.toArray( Hex.fromString( _InPlainIV ) );
b64_IV = Base64.encode( _InPlainIV );
}
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(data);
var returnIVandData:Vector.<String> = new Vector.<String>();
returnIVandData.push( b64_IV );
returnIVandData.push( Base64.encodeByteArray(data) );
return returnIVandData;
}
/**
For Decryption:
Input is expected to be base 64 encoded.
The key is expected to be plain, normal human readable text.
The IV is expected to be base 64 encoded.
Decrypted output is plain, normal human readable text.
*/
public static function decrypt(_InB64Data:String, _InPlainKey:String, _InB64IV:String):String {
var kdata:ByteArray = Hex.toArray(Hex.fromString(_InPlainKey));
var data:ByteArray = Base64.decodeToByteArray(_InB64Data);
var pad:IPad = new PKCS5;
var mode:ICipher = Crypto.getCipher("aes-cbc", kdata, pad);
if (mode is IVMode) {
var ivmode:IVMode = mode as IVMode;
// Just remember this is just a cast. The IV is still being set on the mode variable.
ivmode.IV = Base64.decodeToByteArray( _InB64IV );
}
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(data);
return Hex.toString(Hex.fromArray(data));
}
}
}
Download the sample that has been compiled in Flash Builder and Flash CS5.5(Saved in CS4 Format). Should also work with Flash Develop.