Encryption in Flex Applications 1 - Simulate EncryptedLocalStore(RT)
Posted on 2008-06-20 13:08 moris 阅读(229) 评论(0) 收藏 举报In article 1, I showed a trivial example of using the AS3Crypto API for encrypting data. In this article, we’ll go over an example using Interfaces, Factories, and Encryption to protect code in a SWC library from being easily decompiled.
The first order of business is to create a Flex Library project to hold our protected code, and another Flex Library project to hold the Interface and Factory to access it. In this case, our super-duper-ultra-mega-secret code we want to protect is how to calculate the circumference and area of a circle. I’ve created projects called CircleCalculator and CircleCalculatorInterface. CircleCalculator should reference CircleCalculatorInterface so we can implement the interface we’ll create.
In CircleCalculatorInterface, create an Interface class to define what we want our end-user to be able to do. We’re hiding the code because we don’t want them to be able to decompile our code to see how circle areas and circumferences are calculated.
package com.company
{
public interface ICircleCalculator
{
function calcArea(radius:Number):Number;
function calcCircumference(radius:Number):Number;
}
}Next, in CircleCalculator, create our super-duper-ultra-mega-secret code that implements the ICircleCalculator interface.
package com.company
{
import com.company.ICircleCalculator;
public class CircleCalculator implements ICircleCalculator
{
public function CircleCalculator()
{
}
public function calcArea(radius:Number):Number
{
return Math.PI * radius * radius;
}
public function calcCircumference(radius:Number):Number
{
return 2 * Math.PI * radius;
}
}
}Now that we have the CircleCalculator project in a state that is compiling, open up the bin folder and extract library.swf from CircleCalculator.swc using the zip tool of your choice. Then copy library.swf to the root folder of CircleCalculatorInterface. Library.swf contains the actual code that we’re going to be encrypting.
In order to encrypt library.swf, I’ve created a tool called LibraryEncrypter as an AIR application. It takes any dropped file and encrypts it using blowfish. The key is stored at the beginning of the encrypted bytes. In a real-world scenario, you’d obviously want to do more obfuscation of the key or store it server-side for increased protection.
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" layout="vertical" horizontalAlign="center" verticalAlign="middle"
nativeDragEnter="handleDragEnter(event)"
nativeDragDrop="handleDropSwf(event)"
>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.prng.Random;
private function handleDragEnter(event:NativeDragEvent):void
{
NativeDragManager.acceptDragDrop(this);
}
private function handleDropSwf(event:NativeDragEvent):void
{
var filelist:Array = event.clipboard.getData("air:file list") as Array;
for each(var file:File in filelist)
{
//do simple blowfish encryption for the swf file
var fs:FileStream = new FileStream();
fs.open(file, FileMode.READ);
var fileBytes:ByteArray = new ByteArray();
fs.readBytes(fileBytes);
fs.close();
//generate a random key
var key:ByteArray = new ByteArray();
var random:Random = new Random();
random.nextBytes(key, 8);
var aes:ICipher = Crypto.getCipher("blowfish-ecb", key, Crypto.getPad("pkcs5"));
aes.encrypt(fileBytes);
//rewrite the file with the encrypted blob
fs.open(file, FileMode.WRITE);
fs.writeBytes(key);
fs.writeBytes(fileBytes);
fs.truncate();
fs.close();
fs = null;
Alert.show("Encryption Completed", "Results");
}
}
]]>
</mx:Script>
<mx:Text text="Drop SWF here to encrypt"/>
</mx:WindowedApplication>
Now that that’s done, launch the app and drop library.swf from CircleCalculatorInterface onto it.
If you’re curious, you can drop the encrypted swf into a web browser, right-click and see that “movie not loaded…” will appear. Another test is to use a decompiler tool to ensure the encryption worked ok.
The final step in the process of creating an encrypted swc library is to create a Factory class in CircleCalculatorInterface that can interpret and understand our encrypted library.swf file. You’ll also need to check the box in CircleCalculatorInterface properties for including the AIR libraries. We do this so that our library can be used by either Flex or AIR when we release it to a client.
package com.company
{
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.symmetric.ICipher;
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
import mx.core.ByteArrayAsset;
public class CircleCalculatorFactory extends EventDispatcher
{
//this is the CircleCalculator library.swf file (encrypted with LibraryEncrypter of course)
[Embed (source="library.swf", mimeType="application/octet-stream")]
private var encryptedSwf:Class;
private var _circleCalculator:ICircleCalculator=null;
public function CircleCalculatorFactory(completeHandler:Function)
{
super();
this.addEventListener(Event.COMPLETE, completeHandler);
//load up the swf file that contains the CircleCalculator class
var fileData:ByteArrayAsset = ByteArrayAsset(new encryptedSwf());
var key:ByteArray = new ByteArray();
fileData.readBytes(key, 0, 8);
var encryptedBytes:ByteArray = new ByteArray();
fileData.readBytes(encryptedBytes);
//decrypt library.swf
var aes:ICipher = Crypto.getCipher("blowfish-ecb", key, Crypto.getPad("pkcs5"));
aes.decrypt(encryptedBytes);
//load the swf bytes into the current application domain
var ldr:Loader = new Loader();
var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
//do this for AIR support
if(ldrContext.hasOwnProperty("allowLoadBytesCodeExecution"))
ldrContext.allowLoadBytesCodeExecution = true;
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loadSwfComplete);
ldr.loadBytes(encryptedBytes, ldrContext);
}
private function loadSwfComplete(event:Event):void
{
var cc:Class = ApplicationDomain.currentDomain.getDefinition("com.company.CircleCalculator") as Class;
_circleCalculator = new cc();
dispatchEvent(new Event(Event.COMPLETE));
}
/**
* @return an object implementing the ICircleCalculator interface
*/
public function getInstance():ICircleCalculator
{
return _circleCalculator;
}
}
}Lastly, let’s create an example Flex application that loads and uses our CircleCalculatorInterface library project.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:degrafa="com.degrafa.*" xmlns:paint="com.degrafa.paint.*" xmlns:geometry="com.degrafa.geometry.*"
backgroundGradientColors="[#666666, #222222]"
layout="absolute" viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import com.company.ICircleCalculator;
import com.company.CircleCalculatorFactory;
private var circleCalcFactory:CircleCalculatorFactory = new CircleCalculatorFactory(initComplete);
private var circleCalculator:ICircleCalculator = null;
[Bindable]
private var circumference:Number=0;
[Bindable]
private var area:Number=0;
private function initComplete(event:Event):void
{
circleCalculator = circleCalcFactory.getInstance();
calculateCircle();
}
private function calculateCircle():void
{
circumference = circleCalculator.calcCircumference(radiusSlider.value);
area = circleCalculator.calcArea(radiusSlider.value);
}
]]>
</mx:Script>
<mx:VBox x="20" y="20">
<mx:Label text="Radius:"/>
<mx:HSlider id="radiusSlider" value="100" minimum="10" maximum="400" width="200" change="calculateCircle()" liveDragging="true"/>
<mx:Spacer height="20"/>
<mx:Text text="Circumference: {circumference}"/>
<mx:Text text="Area: {area}"/>
</mx:VBox>
<degrafa:Surface horizontalCenter="0" verticalCenter="0">
<degrafa:fills>
<paint:SolidFill id="blue"
color="#9999ff"/>
</degrafa:fills>
<degrafa:strokes>
<paint:SolidStroke id="white"
color="#FFFFFF"
alpha="1"
weight="2"/>
</degrafa:strokes>
<degrafa:GeometryGroup>
<geometry:Circle fill="{blue}"
stroke="{white}"
radius="{radiusSlider.value}"/>
</degrafa:GeometryGroup>
</degrafa:Surface>
</mx:Application>





浙公网安备 33010602011771号