I'm kind of new to ActionScript 3 at the moment and been trying to use the as3crypto library to encrypt some data with the blowfish algorithm before submitting it to the server for processing. I know you can use https, but most browsers still display the outbound data making it very easy for a user to fake a request. That's why I want to let the user see the page request, but not be able to read the data without decrypting.
Unfortunately for me the deocumentation on the as3crypto library is pretty much non existent aside from comments in the code (which don't help too much). I've set up the flash side of things with a couple static functions to "implement" the as3crypto blowfish encryption and they work fine for encrypting/decrypting within flash only. The problem comes when I try to use the key to decrypt in PHP using the mcrypt library. The output I get is not the original code and I've spent a couple days trying to figure out why to no avail.
Below is the code and explanations. For purposes of this example, the key used was 'mykey' (without the quotes) and the encoded data was 'Hello World' (again without the quotes).
Flash code (as3crypto blowfish helper):
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* @param text The text string to encrypt.
* @param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt:ICipher = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
The output of that varies from run to run, but for the purpose of this example run, the base64 encoded output I get is 'EkKo9htSJUnzBmxc0A=='
When I bring that code into PHP it is base64 decoded before being passed into the method below to decrypt it:
public static function decrypt($crypttext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
$blocksize = mcrypt_enc_get_block_size($td);
$iv = substr($crypttext, 0, $blocksize);
$crypttext = substr($crypttext, $blocksize);
if (true)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
At this point the output is completely unreadable. I suspect the issue may be related to the fact that either the as3crypto implementation of blowfish isn't correct (unlikely) or it could be something to do with the padding it uses (currently null padding) or lastly I've thought it may have something to do with the randomly generated initialization vector in as3crypto not being prepended to the front of the encoded string? That last one I haven't been able to really test because the as3crypto library is large, complicated, and not documented much at all. I've googled this issue and tested everything for a couple days now and I just keep coming up with unusable data in PHP. I know if I can get the Flash to PHP system working, I can reverse engineer it to get the PHP to Flash encryption running as well.
I welcome all input on this matter as it's actually been costing me sleep at night lol Thank you in advance :)
I've done some further testing today and attempted to see if it was the initialization vector as I suspected. I don't believe that's the problem. I modified some things in flash so that I could get an output of the IV used to generate the encoded output:
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* @param text The text string to encrypt.
* @param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
cryptText.position = 0;
var iv:ByteArray = crypt.IV;
iv.position = 0;
trace( Base64.encodeByteArray( iv ) );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
For this example I got an encoded IV of '1bcGpqIbWRc=' and encoded encrypted data of 'XpgART3hNQO10vcgLA==' I plugged those into a modified PHP function after base64_decode() ing them:
public static function decrypt($crypttext,$key,$iv=NULL)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
if( $iv === NULL ){
$ivsize = mcrypt_enc_get_iv_size($td);
echo '<pre>'.$ivsize.'</pre>';
$iv = substr($crypttext, 0, $ivsize);
echo '<pre>'.strlen($iv).'</pre>';
$crypttext = substr($crypttext, $ivsize);
}
if ($iv)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
Even this output is incorrect. I've done some tests to make sure the IV is the correct size both in flash and PHP, but for some reason the PHP side of things just can't decrypt the blowfish encoded output from Flash. I've tried using both NULL and PKCS5 padding in as3crypto and neither works with PHP's system. I've tested to make sure the IV strings are the same in both Flash and PHP. They're both using the same keys. Both are using CFB mode. I don't get it. Same algorithm, same key, same IV, same mode, but they can't decrypt from each other. It's seeming to me that the as3crypto implementation of blowfish may be incorrect. Can anyone confirm this?