Secure Communication Between ActionScript and PHP

Here is the PHP implementation of a custom HTTP POST web service using the 128-bit AES encryption and the CBC mode:

<!--?php if ($_SERVER['REQUEST_METHOD'] != 'POST' || $_SERVER['CONTENT_TYPE'] != 'application/octet-stream') { die('HTTP POST web service awaiting orders'); } $msg = file_get_contents('php://input'); $key = pack('NNNN', 0xdeadbeef, 0xcafebabe, 0xc001d00d, 0xbaadf00d); $iv = $key; $msg = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $msg, MCRYPT_MODE_CBC, $iv); $msg = trim($msg, '\0'); // unpad // Do something with a message received from the client ... // $msg should hold a message to be sent to the client at this point $msg = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $msg, MCRYPT_MODE_CBC, $iv); header('Content-Type: application/octet-stream'); echo $msg; ?-->

And here is the ActionScript consumer of the above service:

package
{
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import com.hurlant.crypto.symmetric.*;

public class Client
{
private var _loader:URLLoader;
private var _mode:CBCMode;
[Embed(source="key.bin", mimeType="application/octet-stream")]
const KEY:Class;

public function Client()
{
_loader = new URLLoader();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
_loader.addEventListener(Event.COMPLETE, OnComplete);
var ba:ByteArray = new KEY();
var key:AESKey = new AESKey(ba);
_mode = new CBCMode(key, new NullPad());
_mode.IV = ba;
}

public function Send(url:String, msg:String):void
{
var ba:ByteArray = new ByteArray();
ba.writeUTFBytes(msg);
var n:int = 16 - ba.length % 16;
for (var i:int = 0; i < n; i++)
{
ba[ba.length] = 0; // pad
}
_mode.encrypt(ba);
var req:URLRequest = new URLRequest(url);
req.method = URLRequestMethod.POST;
req.contentType = "application/octet-stream";
req.data = ba;
_loader.load(req);
}

private function OnComplete(e:Event):void
{
var ba:ByteArray = _loader.data;
_mode.decrypt(ba);
while (ba[ba.length - 1] == 0)
{
ba.length--; // unpad
}
// Do something with a message received from the server ...
}
}
}

It really is that simple. To keep the code short and clean, I deliberately didn’t use any error handling, so this shouldn’t be your production code. I also made one assumption – the message is textual not binary (my actual implementation passes XML encoded messages between the client and the server).

If you wish to pass binaries, I recommend saving the size of the message at the beginning of the stream and use it to properly unpad the decrypted message. In the AES encryption, the size of the message should always be a multiple of 16. If the original message doesn’t meet this requirement, I pad the message with zero bytes before the encryption. The decrypted message thus might contain one or more zero bytes at the end. The text doesn’t contain zero bytes, so you can easily unpad it without knowing the original size of the message. However, the trailing zero bytes might be part of the message when dealing with binaries.

On a side note, the PHP’s XML parser disregards trailing zero bytes but the ActionScript’s XML parser complains with a bogus error. In this case, unpadding is not necessary in PHP but a must in ActionScript.