// ActionScript file
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.util.Hex;

import flash.display.Loader;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import mx.controls.Alert;
import mx.core.UIComponent;

private var encryptFile:File = new File();
private var destFile:File = null;
private var unEncryptedBytes:ByteArray = null;
private var encryptedResult:ByteArray = null;
private var swfLoader:Loader = new Loader();
private var uicom:UIComponent = new UIComponent();

private function init():void
{
    uicom.addChild(swfLoader);
    addChild(uicom);
    uicom.x = 25;
    uicom.y = outputName.y + 125;
}

private function encryptSWF():void
{
    if ( keyText.text.length == 0  )
    {
    Alert.show("Please enter the password.");
    return;
    }
    if ( inputName.text.length == 0 || encryptFile.exists == false )
    {
    Alert.show("Please point to a valid input SWF file.");
    return;
    }
    if ( outputName.text.length == 0 )
    {
    Alert.show("Please type in a valid output file name.");
    return;
    }
    encryptedResult = new ByteArray;
    
    encryptedResult = encryptData(unEncryptedBytes);
    var fileStream:FileStream = new FileStream();            
    fileStream.addEventListener(Event.CLOSE, fileClosed);
    fileStream.addEventListener(IOErrorEvent.IO_ERROR, handleWriteIOError);
    fileStream.openAsync(destFile, FileMode.WRITE);
    
    fileStream.writeBytes(encryptedResult, 0, encryptedResult.length);
    fileStream.close();
}

private function decryptSWF():void
{
    if ( keyText.text.length == 0  )
    {
    Alert.show("Please enter the password.");
    return;
    }
    if ( inputName.text.length == 0 || encryptFile.exists == false )
    {
    Alert.show("Please point to a valid input SWF file.");
    return;
    }
    if ( outputName.text.length == 0 )
    {
    Alert.show("Please type in a valid output file name.");
    return;
    }
    
    //encryptedResult = new ByteArray;
    encryptedResult = decryptData(unEncryptedBytes);
    var fileStream:FileStream = new FileStream();            
    fileStream.addEventListener(Event.CLOSE, fileClosed);
    fileStream.addEventListener(IOErrorEvent.IO_ERROR, handleWriteIOError);
    fileStream.openAsync(destFile, FileMode.WRITE);
    
    fileStream.writeBytes(encryptedResult, 0, encryptedResult.length);
    fileStream.close();
}

private function rot13shiftEnc(dataIn:ByteArray):ByteArray
{
    var dataOut:ByteArray = new ByteArray();
    for ( var i:int = 0; i < dataIn.length; i++ )
    {
        dataOut.writeByte(dataIn[i] + 13);
    }
    return dataOut;
}

private function rot13shiftDec(dataIn:ByteArray):ByteArray
{
    var dataOut:ByteArray = new ByteArray();
    for ( var i:int = 0; i < dataIn.length; i++ )
    {
        dataOut.writeByte(dataIn[i] - 13);            
    }
    return dataOut;
}

private function encryptDES(dataIn:ByteArray):ByteArray
{
    var dataOut:ByteArray = new ByteArray();
    // get key
    if ( keyText.text.length == 0 )
    {
      Alert.show("Please enter the password to encrypt the swf.");
      return null;      
    }
    
    var kdata:ByteArray;
    kdata = Hex.toArray(Hex.fromString(keyText.text));
    if ( kdata.length < 256 )
    {
        for ( var j:int = kdata.length; j < 256; j++ )
        {
            kdata[j] = 0xFF;
        }
    }
    else
        kdata.length = 256;
    var pad:IPad = new NullPad;
    var mode:ICipher = Crypto.getCipher("simple-aes-256-ofb", kdata, pad);
    pad.setBlockSize(mode.getBlockSize());
    dataOut = new ByteArray();
    for ( var i:int = 0; i < dataIn.length; i++ )
    {
    dataOut[i] = dataIn[i];
    }
    dataOut.position = 0;
    mode.encrypt(dataOut);
    dataOut.position = 0;
    return dataOut;
}

private function decryptDES(dataIn:ByteArray):ByteArray
{
    // get key
    var dataOut:ByteArray = new ByteArray();
    if ( keyText.text.length == 0 )
    {
      Alert.show("Please enter the password to decrypt the swf.");
      return null;      
    }
    
    var kdata:ByteArray;
    kdata = Hex.toArray(Hex.fromString(keyText.text));
    if ( kdata.length < 256 )
    {
        for ( var j:int = kdata.length; j < 256; j++ )
        {
            kdata[j] = 0xFF;
        }
    }
    else
        kdata.length = 256;
    
    var pad:IPad = new NullPad;
    var mode:ICipher = Crypto.getCipher("simple-aes-256-ofb", kdata, pad);
    pad.setBlockSize(mode.getBlockSize());
    dataOut = new ByteArray();
    for ( var i:int = 0; i < dataIn.length; i++ )
    {
    dataOut[i] = dataIn[i];
    }
    
    if ( mode is IVMode )
    {
        var ivmode:IVMode = mode as IVMode;
        ivmode.IV = Hex.toArray("");
    }
    mode.decrypt(dataOut);
    return dataOut;
}


private function encryptData(dataIn:ByteArray):ByteArray
{
    //rot13shiftEnc(dataIn, dataOut);
    return encryptDES(dataIn);
}

private function decryptData(dataIn:ByteArray):ByteArray
{
    //rot13shiftDec(dataIn, dataOut);
    return decryptDES(dataIn);
}

private function browseSWF():void
{
    var arr:Array = new Array();
    var swfFilter:FileFilter = new FileFilter("SWF", "*.swf;*.SWF;");
    arr.push(swfFilter);
    encryptFile.addEventListener(Event.SELECT, selectedInputSWF);
    encryptFile.browseForOpen("Select Input SWF File", arr);
}

private function browseSave():void
{
    destFile = new File();
    destFile.addEventListener(Event.SELECT, selectedOutputSWF);
    destFile.browseForSave("Select Input SWF File");
}

private function selectedInputSWF(evt:Event):void
{
    encryptFile.removeEventListener(Event.SELECT, selectedInputSWF);
    inputName.text = encryptFile.nativePath;
    var fileStream:FileStream = new FileStream();            
    fileStream.addEventListener(Event.COMPLETE, fileOpened);
    fileStream.addEventListener(IOErrorEvent.IO_ERROR, handleReadIOError);
    fileStream.openAsync(encryptFile, FileMode.READ);        
}

private function selectedOutputSWF(evt:Event):void
{
    destFile.removeEventListener(Event.SELECT, selectedOutputSWF);
    outputName.text = destFile.nativePath;                     
}

private function handleReadIOError(evt:Event):void
{
    Alert.show("Input SWF Read Error: " + evt);
}


private function handleWriteIOError(evt:Event):void
{
    Alert.show("Output SWF Write Error: " + evt);
}

private function fileOpened(evt:Event):void
{
    var fstream:FileStream = evt.target as FileStream;
    if ( fstream )
    {
        unEncryptedBytes = new ByteArray();
        fstream.readBytes(unEncryptedBytes, 0, fstream.bytesAvailable);
        fstream.close();
        
    }
    else
        trace("bad fstream");
}

private function loadSWF():void
{
    if ( unEncryptedBytes == null || unEncryptedBytes.length < 0 )
    {        
        Alert.show("Please select an unencrypted SWF as the input file.");
        return;        
    }
    trace("loading child SWF (make sure it is the unencrypted swf...)");
    swfLoader.unload();
    swfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleIOError, false, 0, true);
    swfLoader.loadBytes(unEncryptedBytes);
}

private function handleIOError(evt:Event):void
{
    Alert.show("Error injecting swf: " + evt);
}

private function fileClosed(evt:Event):void
{
    var fstream:FileStream = evt.target as FileStream;
    if ( fstream )
    {
        fstream.removeEventListener(Event.CLOSE, fileClosed);        
    }
    else
        trace("bad fstream");
}