Encryption in Flex Applications 3 - NitroLM SWF Encryption(RT)
Posted on 2008-06-20 13:15 moris 阅读(360) 评论(0) 收藏 举报NitroLM (Nitromation License Manager) is a commercial product developed by Simplified Logic, Inc. (SLI) for managing users, products, notifications, and source code protection for applications. It started off as an internal tool to protect SLI’s 3D engineering design and automation software. It quickly grew into a commercial application after some of SLI’s Fortune 500 customers got an appreciation for the design and philosophy behind the NitroLM solution. NitroLM has an API for C/C++, Java, .NET, and recently announced support for Adobe Flex/AIR at 360Flex in Atlanta along with a new marketing video entitled "The Pain of Software Piracy".
The architecture and implementation are fairly straight-forward. SLI has redundant license servers placed in locations around the continental US. SLI provides you with a SWC file to include in your application that communicates with license servers over a secure channel. The interface allows you to manage user registration, various license options (demo/time-limited/floating/checked-out), support/enhancement requests, and sign-on. The only end-user requirement is an Internet connection in order to retrieve a license. A more complete list of features can be found at http://nitrolm.com/Features.html.
You administer a pool of licenses for your company and create and manage your products through a Flex application developed by SLI. The NitroLM API is for communication-only, so the look and feel is up to you. It’s also important to decide what licensing process and features you want to enable in your applications.
Encryption in NitroLM goes beyond what I’ve been able to show in the previous two articles. NitroLM stores decryption keys on the server that can only be accessed after a valid license has been retrieved. The encryption is public/private key encryption as opposed to simple shared-secret encryption.
The process for encrypting an application using NitroLM is to first develop an application you want to protect. I’m going to be lazy and download some example code and call the project UnencryptedFlexApp.
In order to encrypt this application, we first need to create a wrapper project that will handle the login to NitroLM, download a decryption key over a secure connection, and decrypt and display our SWF file.
I’ve created a new project called NitroEncryptedWrapper. Main.swf from UnencryptedFlexApp has been copied into my src folder along with any loose assets and data used by it.
NitroAdmin is the tool used to administer the NitroLM solution. First, I create a new product in the system along with a license key and an encryption key. Both keys are downloaded and placed into my project. The .ser file is a public key which is used to secure the communication to NitroLM. It is unique to each product in the system, and only the server can decrypt messages sent to it with the private key. This prevents any potential interception of the NitroLM server communication. The .vser file is the private key used for encrypting main.swf. We’ll download this key at runtime over a secure connection in order to decrypt our app only after a successful NitroLM authentication has happened. We do not want to distribute either of these files with our application as assets, so pay careful attention during deployment.
Next, I add my product to an existing license pool. If we were setting this up for a new customer, we would have created a new pool of licenses.
The next order of business is to encrypt main.swf using SLI’s SWFEncrypter AIR application. I drag/drop the .ser, .vser, and main.swf onto the SWFEncrypter and click Run.
In the code, I need to embed the encrypted main.swf file and create a connection to NitroLM by using the LicenseClientFactory class. This will be used to create an ILicenseClient compatible object. All communication to NitroLM happens through the ILicenseClient interface. The constructor for LicenseClientFactory takes an event handler function as a parameter. This function will be called once everything NitroLM-related is initialized and ready for use. I also create a ByteArray called decryptedSwfBytes. This ByteArray is bound to a SWFLoader object in mxml with autoLoad=false. We don’t want to load up the embedded swf file until we’re completely done decrypting.
//Put the Flex App's SWF file here that you want to decrypt and run
[Embed(source="main.swf", mimeType="application/octet-stream")]
private var encryptedSwfFile:Class;
private var mainClassName:String = "main";
private var encryptedSwfBytes:ByteArray = new ByteArray();
[Bindable]
private var decryptedSwfBytes:ByteArray = new ByteArray();
private var serPublicKey:ByteArray = new ByteArray();
private var publicKey:RSAKey = null;
private var productName:String = null;
private var licenseClientFactory:LicenseClientFactory = new LicenseClientFactory(initNitroLM);
private var licenseClient:ILicenseClient = null;
In initNitroLM(), we validate our license and retrieve a decryption key if we have a license. Otherwise, we pop up a Login dialog box to retrieve a license.
/**
* Load the swf file into a ByteArray and check for a license on startup
*/
private function initNitroLM(event:Event):void
{
serPublicKey.length = 0;
encryptedSwfBytes.length = 0;
if(encryptedBlobBytes != null)
encryptedBlobBytes.length = 0;
//get the basic data from the encrypted blob
var encryptedBlobBytes:ByteArray = new encryptedSwfFile();
productName = encryptedBlobBytes.readUTF();
var keyLength:int = encryptedBlobBytes.readInt();
encryptedBlobBytes.readBytes(serPublicKey, 0, keyLength);
encryptedBlobBytes.readBytes(encryptedSwfBytes);
//save the public key in the NitroLM Interface
//so we can communicate to the server over an
//encrypted channel
ProductKeys.putPublicKey(productName, serPublicKey);
licenseClient = licenseClientFactory.getInstance();
var licenseValues:HashMap = new HashMap();
var response:int = licenseClient.validate("0.1", productName, licenseValues);
if(response == NLMConstants.RESPONSE_OK)
{
trace(licenseValues.dump());
//we already have a license, get the decryption key from server
licenseClient.addEventListener(LicenseClientEvent.LICENSE_RESPONSE, handleRequestKey);
licenseClient.requestKey(productName, "0.1");
}
else
{
//retrieve a license. pop up dialog box here
var login:Login = new Login();
login.licenseClient = licenseClient;
login.product_name = productName;
login.addEventListener("success", loginSuccess); //re-run init
login.addEventListener("failure", loginFailure);
PopUpManager.addPopUp(login, this, true);
PopUpManager.centerPopUp(login);
login.email.setFocus();
}
}
If we get a valid license, we request a key and handle the event that comes back from the server. We then decrypt and set the SWFLoader to visible.
/**
* This method retrieves a decryption key from the server based on
* our valid and authenticated license we retrieved
*/
private function handleRequestKey(event:LicenseClientEvent):void
{
licenseClient.removeEventListener(LicenseClientEvent.LICENSE_RESPONSE, handleRequestKey);
if(event.response == NLMConstants.RESPONSE_OK)
{
var retVals:HashMap = event.data;
var key:ByteArray = retVals.find("key");
key.position = 0;
var rsaKey:RSAKey = ProductKeys.readRSAPublicKey(key);
decryptedSwfBytes.length = 0;
//now decrypt and load the swf file
rsaKey.verify(encryptedSwfBytes, decryptedSwfBytes, 128);
decryptedSwfBytes.writeBytes(encryptedSwfBytes, encryptedSwfBytes.position);
loader.load();
loader.visible = true;
}
else
{
Alert.show(NLMConstants.responseToString(event.response), "Error");
}
}
See the source code for additional details and to view the Login dialog box code.
NitroEncryptedWrapper example







浙公网安备 33010602011771号