Home  >  

Encryption in Flex Applications 3 - NitroLM SWF Encryption

AddThis Social Bookmark Button

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".

NitroLM_architecture.jpg

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.

UnencryptedFlexApp example

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.

NitroEncryptedWrapper_projectstructure.png

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_productkeys.png

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.

nitroadmin_poolsetup.png

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.

 

 

 

 

swfencrypter.png

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;
NitroEncryptedWrapper_beforelogin.png

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();
  	}
}
NitroEncryptedWrapper_afterlogin.png

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

Read more from Andrew Westberg. Andrew Westberg's Atom feed andrewwestberg on Twitter

Comments

3 Comments

Raul Riera said:

You have to noticed how he didnt wash his hands when he touch his hair.

Jürgen said:

"The only end-user requirement is an Internet connection in order to retrieve a license."

Is an internet connection needed just once in the installation process or on every startup of the software? We want to license an AIR application that can be run offline as well.

@Jürgen Thanks for the question. For Nitro-LM, an internet connection is only required once to retrieve a license. There are 3 license types (Demo, Floating, and Checkout). Demo, and Checkout licenses can run in an online/offline mode where you have one license per user. Floating licenses are a a concurrent user license where a group of people share licenses and return them to the server when the application closes. The licenses can "float" to the currently active users to reduce your total license requirements.

This article is becoming quite dated. Look at the simplified logic nitro-lm blog for the latest info. I'll try to get some updated articles here once the new release of the administration tool is completed.

Leave a comment


Type the characters you see in the picture above.

Tag Cloud

Poll: Sci-Fi Movies

What's Your Favorite Sci-Fi Movie of All Time?

Vote | View Poll Results | Read Related Blog Entry

Latest Features

  •     Welcome back to the series. This time we are goings to build a really exciting component that will be used to simply display information about the user. Well, you might say why to we need such a component, is there... Continue Reading
  •    Welcome back to our exciting Facebook ActionScript series. In this article we will discuss one of most important (and most exciting) features of the FB platform, it's the publishing of news. We all know when we log in to facebook,... Continue Reading
  • This article provides 10 tips and best practices (in no particular order) for maximizing the benefits that Dojo can bring to your next project. For a more thorough introduction to Dojo, see the article Dojo: The JavaScript Toolkit with... Continue Reading
  •     The notifications are one of the most interesting (and important) parts of the facebook area. In order to completely understand the Flash side of it, we need to understand the basics of the facebook notification, what it is and how... Continue Reading

Development Series

Get an overview of the tools and technologies that work together to allow developers to build Rich Internet Applications (RIAs) quickly and easily.

facebook icon Facebook Application Development

Anatomy of an Enterprise Flex RIA

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.