Birds-Eye.Net
All things broadband and more...
 
Web Birds-Eye.Net
What's New?

Download Purchased Items

Research:
Analysis
International

Reference:
Acronyms & Definitions
Articles
Broadband Directory
Legacy
Operations
Technical
Yearly Predictions
> RSS Feeds <

Business Forms:
Due Diligence Checklist
Funding & VC Due Diligence
Real Estate Due Diligence

Resources:
Monitoring/Reporting/Benchmarking
Patent Harvesting Kit
Ready to Use Scripts
Source Code

Referral:
Expert Consulting
Referral

Other:
Advertise With Us
Feedback
Recommended Reading
Fishing
House
Baby in the City
Blog

Simple But Effective Software License Management
A step by step example of a "good enough" software license management system

By: Bruce Bahlmann - Contributing Author (your feedback is important to us!)

Created: April 3, 2007

One of the first challenges of any good software company begins with protecting their investment. Software license management offers a way to control access to your software while allowing you to license various features without the costs of re-distribution.

The goal of any good software license management process is to restrict use of an application and prevent theft or exploited use as well as meet the following operational requirements: 

  • Restriction on use of an executable (so as to permit LOW RISK evaluations to happen and encourage these users to UPGRADE to full priced licensed releases).
  • Linkage between an executable, the order (i.e. the customer and $), and some restriction to prevent sharing of licenses as it gives up the identity of the original buyer.
  • The ability to simply swap out a license file to increase functionality (no additional install required).

A fairly easy way to meet these requirements without paying a fortune in development costs is to use a standalone license file model as described below. The following model uses order number, encryption, product release information, and some basic feature keying to accomplish the goals above. A more comprehensive variant of this method would implement a key value pair system for keying zero or more product features within the license file while making this system infinitely more flexible. Too keep things simple, the following model uses a fixed delimiter as a means of allowing the license file to key multiple aspects of the application but as just mentioned this is inferior to using key value pairs.

Following the simple model, the license file MUST be named as follows:

<product name>_<order number>.lic

  • Product name links the file name with the internal name given to the application it is attempting to license. Note this should have little (if any) to do with the actual name of the application file name. Such that if the application file name was renamed, it would still continue to use the same license file so such renaming would have no impact on which license file the application looks for.
  • The order number links the customer with the product name such that if the user of a given application shares his license file with someone their order number goes with it.
  • Finally, the ".lic" extension provides an obvious indicator of what the file does.

Inside the file are a number of fields - each with a very specific purpose:

<random number>_<product name>:<order number>|<major version>;<restriction>

For example: xyzapp_2TG82317RK6513331.lic would contain the following information

430599247240560_ xyzapp: 2TG82317RK6513331|1.x;0

For example:

  • Random Number: 430599247240560 (text string less than 20 characters ' allows each license to be represented by a different string even though they are equivalent)
  • Product Name: xyzapp(text string less than 20 characters)
  • Order Number: 2TG82317RK6513331 (text string less than 20 characters)
  • Major Version: 1.x (three character sting that indicates the major version)
  • Restriction: 0 (7 digital integers ' 0=no restrictions, -1=prevent all functions, or some positive number specifying a limitation such as number of clients)

This license file is created by the website during the sales process. The buyer, must download and install their license for any applications to work. Installation could be as easy as moving the file to the same directory as the application or as sophisticated as loading a registry key or running some application to download and install the license file to the proper location on the file system. Each executable or obvious utility should require a license to operate correctly. The exception might be executables for data manipulation or some other non-intended use.

How to process the license file:

  • Program will look for a license a (.lic) file beginning with its same name (e.g. xyzapp will look for a license file beginning with xyzapp). If a license file DOES NOT exist, the executable will terminate with: Program Aborted: License File MISSING ' Error#001'. If multiple xyzapp license files exist, it will grab the first one it finds (or alternatively the one with the most recent creation date). Ideally there should not be multiples but in the case of an upgrade from evaluation to full release, there could be two files.
  • Upon selecting the file, store the full filename and parse out the program name and the order number for future validation use.
  • Read in the contents of the file and decrypt using the shared key:

my $cipher_key = "0123456789ABCDEF"; # Exactly 8 bytes

  • Parse out the contents of the decrypted string using the delimiters described above ' the delimiters are intentionally not all the same but will appear in the order as described earlier into their associated variables. Alternatively, if key value pairs were used that would eliminate the need for delimiters.
  • First TEST: check to see that the program name and order number in the decrypted string are same as the filename. If they are NOT equal, exit executable with: 'Program Aborted: License Invalid ' Error#101'. If test is successful, the license can be interpreted further'
  • Second TEST: check to see if the version of the program is less than or equal to the version in the license. This requires that the version of the program be hard coded and available at the time this license test is performed. If the version of the executable is 1.12 and the license is 1.x, the license should be interpreted as being valid. If the version of the executable is 2.11 and the license file version is 1.x then exit executable with: 'Program Aborted: License Invalid ' Error#201'.
  • If the license file passes both tests, it should be interpreted as being VALID, the last step is to see what if any restrictions on executable operation to apply. This field can be applied with varying levels of sophistication or simplification. Basically there are three different levels:
    • "-1" To allow the restriction of operation. Meaning, that if someone obtains this license, it won't work. As such, if the executable finds such a file, it will exit the program with the following: 'Program Aborted: License Invalid ' Error#301'.
    • "0" To allow unrestricted use of all the features of an application.
    • "1" or some other number like 50000 To allow some level of restriction of the executable. How this is implemented may vary. For example, it could be that any positive integer would limit transactions to 10. Or one could just take the number in the license and set the transaction limit to that number such as 50000 or the maximum if this number exceeds the maximum.

Included below is the code for two perl programs that encrypt or decrypt a file using DES and the cipher key mentioned above.

[lm-encrypt.pl]

my $cipher_key = "1F492C7E80AD6B53";    # Exactly 8 bytes
my $filename = "memu_2TG82317RK6513331";
my $string;
open F, "$filename\.txt";
my @raw = <F>;
close F;

foreach (@raw) {
    chomp;
    next if ($_ eq '');
    $string = $_;
}

open F, ">$filename\.lic";
print F &encrypt_payload($string);
close F;

#####################################################################

sub encrypt_payload {
    my ($payload) = @_;
    my $cypher_str;
    my $i;
    my $substring;
    use Crypt::DES;
    my $key = pack("H16", $prog{'cipher_key'});  # min. 8 bytes
    my $cipher = new Crypt::DES $key;
    ## cypher only works on text of exactly 8 bytes (PAD if necessary)
    my $len = length($payload);
    my $loop = int ($len/8);
    $loop++ if ($len%8 >0);
    for ($i=0; $i<$loop; $i++) {
        $substring = substr($payload, $i*8, 8);
        if (($len = length $substring)!= 8) {
            ## PAD string with NULL characters to make it exactly equal 8 bytes
            $substring .= "\0" x (8 - $len);
        }
        $cypher_str .= unpack("H16", $cipher->encrypt($substring));
    }
    return ($cypher_str);   
}

[lm-decrypt.pl]

my $cipher_key = "0123456789ABCDEF"; # Exactly 8 bytes
my $filename = "memu_2TG82317RK6513331";
my $string;
open F, "$filename\.lic";
my @enc = <F>;
close F;

foreach (@enc) {
    chomp;
    next if ($_ eq '');
    $string = $_;
}

open F, ">$filename\-original\.txt";
print F &decrypt_payload($string);
close F;

## business rules for interpreting decrypted file

#####################################################################

sub decrypt_payload {
    my ($payload) = @_;
    my $decypher_str;
    my $i;

    use Crypt::DES;
    my $key = pack("H16", $prog{'cipher_key'});  # min. 8 bytes
    my $cipher = new Crypt::DES $key;
    ## decypher only works in in reverse of cypher (blocks of 16) but is exact multiples
    my $len = length($payload);
    my $loop = $len/16;
    if ($len%16 != 0) {
        ## Encrypted string has been tampered or encryption scheme has been upgraded
        return ("error007-URL is invalid, click the link directly or re-attempt copy and paste");
    }

    ## check for the existence of a payload and if it contains all uppercase hex
    my $temp_payload = $payload;
    $temp_payload =~ s/[A-F0-9]//g;
    #exit(0) if (($payload eq '')||($temp_payload eq ''));
    for ($i=0; $i<$loop; $i++) {
        $decypher_str .= $cipher->decrypt(pack("H16", substr($payload, $i*16, 16)));
    }

    ## Exit if string was not first frozen -- hack attack
    #exit(0) if ($decypher_str !~ /^FrT/);
    ## Remove any trailing NULL/PAD characters from decrypted string

    $decypher_str =~ s/\0*$//;
    return ($decypher_str);
}

Can Birds-Eye.Net help you or your Company?
Receive your Birds-Eye.Net articles and white papers hot off the presses by adding our RSS feed to your reader.

(C) Copyright Birds-Eye.Net, All rights reserved.
It is against the law to reproduce this content or any portion of it in any form without the explicit written permission of Birds-Eye Network Services, LLC. Federal copyright law (17 USC 504) makes it illegal, punishable with fines up to $100,000 per violation plus attorney's fees.