субота, 11 лютого 2012 р.

Encryption AS3+PHP

I recently faced the problem of encrypting files using php and decrypting them using as3 (AIR app). There are a lot of information about it but I could not find a solution of to this problem. In some time I was able to define relations between php and as3 and I want to share it with you.


So, we have the following problem: We should encrypt the file (eg image) with AES-128 using php and decrypt it using air application.
We need: 
  1. As3Crypto library
  2. Adobe Flash Builder
  3. Apache or other.

First of all let's create a php-file to encrypt image file. We also need a key (must have only 32 characters) and iv - initiallization vector (must have only 16 characters) in case when we encrypt with AES-128. AES-128 is MCRYPT_RIJNDAEL in php. But MCRYPT_RIJNDAEL_256 not equal AES-256!!! Let's use cbc-mode because it's the most safe mode.
<?php
    $file           = 'myimage.jpg';
    $encrypted_file = 'encrypted_image.jpg';

    $file_content = file_get_contents($file);
    $key = 'PasswordpasswordPasswordpassword'; // 32 characters
    $iv  = 'AANoTherPassword'; // 16 characters
    
    // encrypt with AES-128
    $plaintext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $file_content, MCRYPT_MODE_CBC, $iv);
    
    $newfile = fopen($encrypted_file, 'wb');
    fwrite($newfile, $plaintext);    
    fclose($newfile);    
?>
We've got a new encrypted file after running php script.
Follow the steps below to make an AIR app that will decrypt new file and load it.
Figure 1
  1. Start by creating a new AIR project in Flex Builder
  2. Name the main application file DecryptApp.mxml (Figure 1)
  3. Download the as3crypto library (swc file) from the project on google code
  4. Place as3crypto.swc in your AIR project’s libs folder (Figure 2)
  5. Copy the code below and replace everything in DecryptApp.mxml with it
Figure 2
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       backgroundColor="#323232" styleName="plain" width="100%" height="100%">
    
    <s:nativeDragEnter>
        if (event.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
        {
        var files:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
        
        // only allow a single file to be dragged in
        if (files.length == 1)
        {
        DragManager.acceptDragDrop(event.currentTarget as IUIComponent);
        setStyle("backgroundColor", 0xccccff);
        }
        }
    </s:nativeDragEnter>
    
    <s:nativeDragExit>
        // Event handler for when the drag leaves the WindowedApplication
        setStyle("backgroundColor", 0x323232);
    </s:nativeDragExit>
    
    <s:nativeDragDrop>
        // Event handler for when a dragged item is dropped on the WindowedApplication
        var arr:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
        //startImage.source = (arr[0] as File).url;
        var file:File = arr[0] as File;
        loadimage(file);
    </s:nativeDragDrop>
    
    <fx:Script>
        <![CDATA[
            import mx.core.IUIComponent;
            import mx.managers.DragManager;
            
            import com.hurlant.crypto.Crypto;
            import com.hurlant.crypto.symmetric.*;
            import com.hurlant.util.Hex;
            
            private var fs:FileStream;
            
            private function loadimage(file:File):void
            {
                fs = new FileStream();
                fs.addEventListener(Event.COMPLETE, onFileRead);
                fs.openAsync(file, FileMode.READ);
            }
            
            private function onFileRead(event:Event):void 
            {
                var ba:ByteArray = new ByteArray();
                fs.readBytes(ba, 0, fs.bytesAvailable);
                fs.close();
                
                // decrypt
                ba = decrypt(ba); 
                
                startImage.load(ba);
            }
            
            private function decrypt(input:ByteArray):ByteArray
            {
                var key:ByteArray = Hex.toArray(Hex.fromString("PasswordpasswordPasswordpassword"));                
                var pad:IPad = new NullPad();
                var aes:ICipher = Crypto.getCipher("aes-cbc", key, pad);
                var ivmode:IVMode = aes as IVMode;
                ivmode.IV = Hex.toArray(Hex.fromString("AANoTherPassword"));            
                aes.decrypt(input);            
                return input;
            }
        ]]>
    </fx:Script>
    
    
    <mx:ViewStack id="startVS" width="100%" height="100%" creationPolicy="all">
        <mx:Canvas width="100%" height="100%">
            <mx:Text verticalCenter="0" horizontalCenter="0" color="white">
                <mx:htmlText><![CDATA[<font size="20"><b>Drag your encrypted image file here</b></font>]]></mx:htmlText>
            </mx:Text>
        </mx:Canvas>
        <mx:Canvas width="100%" height="100%">
            <mx:Image id="startImage" width="100%" height="100%" horizontalAlign="center" verticalAlign="middle" complete="startVS.selectedIndex = 1;"/>
        </mx:Canvas>
    </mx:ViewStack>
</s:WindowedApplication>

Run the DecryptApp. Minimize Flex builder and drag the “encrypted_image.jpg” file from your desktop(or other place) and drop it on the DecryptApp. You should see your image displayed in DecryptApp in a few seconds.

Addition: The flex source files and php files are here.