<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2008://34.23250-</id>
  <updated>2009-11-05T20:15:17Z</updated>
  <title>Comments for Encryption in Flex Applications 3 - NitroLM SWF Encryption (http://www.insideria.com/2008/04/encryption-in-flex-application-2.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2008://34.23250</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=23250" title="Encryption in Flex Applications 3 - NitroLM SWF Encryption" />
    <published>2008-04-04T15:00:00Z</published>
    <updated>2008-04-08T15:06:18Z</updated>
    <title>Encryption in Flex Applications 3 - NitroLM SWF Encryption</title>
    <summary> 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&#8217;s 3D engineering design and...</summary>
    <author>
      <name>Andrew Westberg</name>
      <uri>http://www.flexjunk.com</uri>
    </author>
    
    <category term="Blogs" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<p>
<a href="http://nitrolm.com">NitroLM</a> (Nitromation License Manager) is a commercial product developed by <a href="http://simplifiedlogic.com">Simplified Logic, Inc. (SLI)</a> for managing users, products, notifications, and source code protection for applications.  It started off as an internal tool to protect SLI&#8217;s 3D engineering design and automation software.  It quickly grew into a commercial application after some of SLI&#8217;s Fortune 500 customers got an appreciation for the <a href="http://www.webbuyersguide.com/bguide/Whitepaper/brief.asp?wpId=MTEyMDY&hidResTypeid=1&src=simplifiedlogicpromo&sitename=webbuyersguide">design and philosophy</a> 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".
</p>
<p>
<object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/ldbr8Sy5Hq0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/ldbr8Sy5Hq0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object>
</p>

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroLM_architecture.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroLM_architecture.jpg" alt="NitroLM_architecture.jpg" title="Click to enlarge" width="148"/></a></div>
<p>
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 <a href="http://nitrolm.com/Features.html">http://nitrolm.com/Features.html</a>. 
</p>
<p>
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&#8217;s also important to decide what licensing process and features you want to enable in your applications.
</p>
<p>
Encryption in NitroLM goes beyond what I&#8217;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.
</p>
<p>
The process for encrypting an application using NitroLM is to first develop an application you want to protect.  I&#8217;m going to be lazy and download some example code and call the project UnencryptedFlexApp.
</p>
<p>
<a href="http://flexjunk.com/examples/UnencryptedFlexApp/main.html">UnencryptedFlexApp example</a>
</p>
<p>
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.
</p>

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_projectstructure.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_projectstructure.png" alt="NitroEncryptedWrapper_projectstructure.png" title="Click to enlarge" width="148"/></a></div>
<p>
I&#8217;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.
</p>

<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/nitroadmin_productkeys.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/nitroadmin_productkeys.png" alt="nitroadmin_productkeys.png" title="Click to enlarge" width="148"/></a></div>
<p>
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&#8217;ll download this key at runtime over a secure connection in order to decrypt our app only <strong>after</strong> 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.
</p>

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/nitroadmin_poolsetup.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/nitroadmin_poolsetup.png" alt="nitroadmin_poolsetup.png" title="Click to enlarge" width="148"/></a></div>
<p>
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.
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/swfencrypter.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/swfencrypter.png" alt="swfencrypter.png" title="Click to enlarge" width="148"/></a></div>
<p>
The next order of business is to encrypt main.swf using SLI&#8217;s SWFEncrypter AIR application.  I drag/drop the .ser, .vser, and main.swf onto the SWFEncrypter and click Run.
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>
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&#8217;t want to load up the embedded swf file until we&#8217;re completely done decrypting.
</p>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre> 

<span class="linecomment">//Put the Flex App's SWF file here that you want to decrypt and run</span>
[Embed(source="<span class="quote">main.swf</span>", mimeType="<span class="quote">application/octet-stream</span>")]
<span class="category1">private</span> <span class="category1">var</span> encryptedSwfFile:Class;
<span class="category1">private</span> <span class="category1">var</span> mainClassName:<span class="category2">String</span> = "<span class="quote">main</span>";
			
<span class="category1">private</span> <span class="category1">var</span> encryptedSwfBytes:ByteArray = <span class="category1">new</span> ByteArray();
[Bindable]
<span class="category1">private</span> <span class="category1">var</span> decryptedSwfBytes:ByteArray = <span class="category1">new</span> ByteArray();
			
<span class="category1">private</span> <span class="category1">var</span> serPublicKey:ByteArray = <span class="category1">new</span> ByteArray();
<span class="category1">private</span> <span class="category1">var</span> publicKey:RSAKey = <span class="category1">null</span>;
<span class="category1">private</span> <span class="category1">var</span> productName:<span class="category2">String</span> = <span class="category1">null</span>;
			
<span class="category1">private</span> <span class="category1">var</span> licenseClientFactory:LicenseClientFactory = <span class="category1">new</span> LicenseClientFactory(initNitroLM);
<span class="category1">private</span> <span class="category1">var</span> licenseClient:ILicenseClient = <span class="category1">null</span>;</pre>
</code>
 
</div></div> 

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_beforelogin.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_beforelogin.png" alt="NitroEncryptedWrapper_beforelogin.png" title="Click to enlarge" width="148"/></a></div>
<p>
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.
</p>
 <div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre> 
<span class="blockcomment">/**
 * Load the swf file into a ByteArray and check for a license on startup
 */</span>
<span class="category1">private</span> <span class="category1">function</span> initNitroLM(event:Event):<span class="category1">void</span>
{
 	serPublicKey.<span class="category2">length</span> = 0;
 	encryptedSwfBytes.<span class="category2">length</span> = 0;
 	<span class="category1">if</span>(encryptedBlobBytes != <span class="category1">null</span>)
 		encryptedBlobBytes.<span class="category2">length</span> = 0;
 				
 	<span class="linecomment">//get the basic data from the encrypted blob</span>
 	<span class="category1">var</span> encryptedBlobBytes:ByteArray = <span class="category1">new</span> encryptedSwfFile();
 	productName = encryptedBlobBytes.readUTF();
 	<span class="category1">var</span> keyLength:<span class="category1">int</span> = encryptedBlobBytes.readInt();
 	encryptedBlobBytes.readBytes(serPublicKey, 0, keyLength);
 	encryptedBlobBytes.readBytes(encryptedSwfBytes);
 
 	<span class="linecomment">//save the public key in the NitroLM Interface</span>
 	<span class="linecomment">//so we can communicate to the server over an</span>
 	<span class="linecomment">//encrypted channel</span>
 	ProductKeys.putPublicKey(productName, serPublicKey);
 				
 	licenseClient = licenseClientFactory.getInstance();
 				
 	<span class="category1">var</span> licenseValues:HashMap = <span class="category1">new</span> HashMap();
 	<span class="category1">var</span> response:<span class="category1">int</span> = licenseClient.validate("<span class="quote">0.1</span>", productName, licenseValues);
 	<span class="category1">if</span>(response == NLMConstants.RESPONSE_OK)
 	{
  		<span class="category2">trace</span>(licenseValues.dump());
  		<span class="linecomment">//we already have a license, get the decryption key from server</span>
  		licenseClient.addEventListener(LicenseClientEvent.LICENSE_RESPONSE, handleRequestKey);
  		licenseClient.requestKey(productName, "<span class="quote">0.1</span>");
  	}
 	<span class="category1">else</span>
 	{
  		<span class="linecomment">//retrieve a license.  pop up dialog box here</span>
  		<span class="category1">var</span> login:Login = <span class="category1">new</span> Login();
  		login.licenseClient = licenseClient;
  		login.product_name = productName;
  		login.addEventListener("<span class="quote">success</span>", loginSuccess); <span class="linecomment">//re-run init</span>
  		login.addEventListener("<span class="quote">failure</span>", loginFailure);
  					
  		PopUpManager.addPopUp(login, <span class="category1">this</span>, <span class="category1">true</span>);
  		PopUpManager.centerPopUp(login);
  		login.email.<span class="category2">setFocus</span>();
  	}
}</pre>
</code>
 
</div></div> 

<div class="ap_r" style="margin: 16px;"><a href="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_afterlogin.png" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/upload/2008/03/encryption_in_flex_application_2/NitroEncryptedWrapper_afterlogin.png" alt="NitroEncryptedWrapper_afterlogin.png" title="Click to enlarge" width="148"/></a></div>
<p>
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.
</p>
 <div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre> 

<span class="blockcomment">/**
 * This method retrieves a decryption key from the server based on
 * our valid and authenticated license we retrieved
 */</span>
<span class="category1">private</span> <span class="category1">function</span> handleRequestKey(event:LicenseClientEvent):<span class="category1">void</span>
{
 	licenseClient.removeEventListener(LicenseClientEvent.LICENSE_RESPONSE, handleRequestKey);
 	<span class="category1">if</span>(event.response == NLMConstants.RESPONSE_OK)
 	{
  		<span class="category1">var</span> retVals:HashMap = event.<span class="category2">data</span>;
  		<span class="category1">var</span> key:ByteArray = retVals.find("<span class="quote">key</span>");
  		key.<span class="category2">position</span> = 0;
  		<span class="category1">var</span> rsaKey:RSAKey = ProductKeys.readRSAPublicKey(key);
  		decryptedSwfBytes.<span class="category2">length</span> = 0;
  					
  		<span class="linecomment">//now decrypt and load the swf file</span>
  		rsaKey.verify(encryptedSwfBytes, decryptedSwfBytes, 128);
  					
  		decryptedSwfBytes.writeBytes(encryptedSwfBytes, encryptedSwfBytes.<span class="category2">position</span>);
  
  		loader.<span class="category2">load</span>();
  		loader.<span class="category2">visible</span> = <span class="category1">true</span>;
  	}
 	<span class="category1">else</span>
 	{
  		Alert.<span class="category2">show</span>(NLMConstants.responseToString(event.response), "<span class="quote">Error</span>");
  	}
}</pre>
</code>
 
</div></div> 
<p>
See the source code for additional details and to view the Login dialog box code.<br/>
<a href="http://flexjunk.com/examples/NitroEncryptedWrapper/NitroEncryptedWrapper.html">NitroEncryptedWrapper example</a>
</p>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23250-comment:2016381</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23250" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html#comment-2016381" />
    <title>Comment from Raul Riera on 2008-04-04</title>
    <author>
        <name>Raul Riera</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>You have to noticed how he didnt wash his hands when he touch his hair.</p>]]>
    </content>
    <published>2008-04-04T18:03:58Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23250-comment:2056771</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23250" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html#comment-2056771" />
    <title>Comment from Jürgen on 2009-03-29</title>
    <author>
        <name>Jürgen</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>"The only end-user requirement is an Internet connection in order to retrieve a license."</p>

<p>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.</p>]]>
    </content>
    <published>2009-03-30T06:21:08Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.23250-comment:2056778</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.23250" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/04/encryption-in-flex-application-2.html#comment-2056778" />
    <title>Comment from Andrew Westberg on 2009-03-30</title>
    <author>
        <name>Andrew Westberg</name>
        <uri>http://www.flexjunk.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.flexjunk.com">
        <![CDATA[<p>@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.</p>

<p>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.</p>]]>
    </content>
    <published>2009-03-30T11:37:27Z</published>
  </entry>

</feed
