Click here to Skip to main content
Click here to Skip to main content

RSA License Protection

, 30 May 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Implementing License Protection using RSA

Introduction

The purpose of this article is to demonstrate a reasonably quick and effective method of license protection using the .NET framework's built-in RSA cryptography components to digitally sign and verify license terms for an application.

Background

Almost anyone who has produced a sellable bit of software is going to be concerned (at least a little) with unauthorized distribution of their program - if only because it is often easier to pirate software than it is to legitimately buy it. This is the key when securing software for copy protection: It should be easier to buy than to pirate. The best bit of programming you can do to secure your program is to make the program actually valuable to the user, so they want to buy it. But, the next best thing is a mechanism by which you can use to correctly identify valid users of the program. There is no end to these methods, and they all have varying levels of security, administration overhead, and user-annoyance. Here are some of the common methods:

Serial Number Protection

Found on the back of a CD case, the most common copy-protection you can find often involves a long serial number that is derived from an algorithm, such that only the original key-generator can produce valid keys. Often, the first few characters define a seed entry for a pseudo-random-number generator, and the remaining characters must match the transformed output of that number generator. This has a number of drawbacks:

  1. It is a blanket authorization: Usernames and License-end terms, partial licenses cannot be specified
  2. All you need is a copy of the serial-number: there are hundreds of websites that list known serial numbers for almost any bit of commercial software.
  3. The user has to type in a long annoying and difficult to read serial number in order to install the software.

Online Activation

An extension of serial-number protection: the application contacts a central server to validate that the serial-number is one that has been issued. This allows serial numbers to be blacklisted, tracked, etc. The main drawback is that the application must have internet access in order to validate the serial number. Users will probably not be happy about this (especially if they don't have constant internet access) and you may find hackers patching your software not to illegally copy it, but just to get it to work offline. The other drawback is the amount of coding and development work that must go into a system like this that could be defeated by a proxy-server that simulates the responses of your own validation server.

License Terms File

Many systems use a license file that is supplied to the user with their purchase. The license file specifies the licensee (the user's name, address, contact details, etc.), the product being licensed, and the start and end dates of that license. The software asks for the license file on first use, copies it into a known location, then validates that the terms of the license are valid (correct software version, within the applicable date-range, etc.).

The trick here is to ensure that the license file that is supplied is authentic, if that part is covered, this is an excellent system for licensing: the license terms can be as simple or complex as you like (i.e. blanket authorization, or partial (certain features enabled)), they can have start and end dates, be restricted to particular applications or even restricted to particular users. The user isn't forced to type in a long and complex serial-number, and having the users name and contact details embedded within the terms makes it less likely that users will voluntarily share the license file.

Authenticating the License File

There is a branch of cryptography that deals with verification (or signing) of data, using Asymmetrical Encryption.

A digital signature is produced from the data being verified by generating a hash-code from the source data, and encrypting this hash with a private key.
The hash code will be unique to the source data... if even one bit in the source data changes, the resulting hashcode will be quite different. (The "strength" of any hashing algorithm is indicated by how much the hash-code changes with the smallest possible edit of the source data).

Verification of the data is achieved by using the public-part of the key to check if the digital signature (the encrypted hash) still matches the data that is being verified. If any part of the data is changed, then the digital signature will not match.

This means that you can verify that the license file the system is using definitely came from you, (the sellers of the software) without having to give the application access to the private key. If you were to use symmetrical encryption to encrypt the license-terms (so they could not be seen or changed), then the application itself would need access to the encryption key, in order to decrypt the file. The key could be found within the application EXE and extracted, allowing pirates to generate their own license files.

Using asymmetrical encryption still requires that the application have access to the public part of the key, but knowing the public part of the key will not help anyone trying to hack the system.

The danger lies in pirates being able to replace or intercept the public key with one of their own making. This would require them to get into the .exe and alter the sequence of bytes that defines the public-key (whether it is a string-literal or a resource within the EXE).

This is beyond the scope I have given myself for this article, but just a quick mention:
signing the executable itself is one potential way of trying to stop this: modification of the executable will generate a different signature, and the application can be instructed not to open. (This is how the click-once manifests work, in fact, using click-once to deploy your application makes it (almost) impossible to modify that application without regenerating the click-once manifest file.)

Using the Code

The logic for the licensing system is contained within the General.Security namespace within the example project: this code is non-specific and portable (it doesn't reference any custom types outside the General namespace) and the two files (Serializer.cs and RSA.cs) can be moved to any project without change. The actual implementation of the licensing system (i.e. project specific code) is contained within the validateLicenseFile() method of the static Program class. This provides a good example of using the methods defined in the General.Security namespace. The Program.validateLicenseFile() method reads the public key out of the embedded resource (Resources.resx) and locates the license file (asking the user for the location if it can't find it). It verifies the license file signature is correct, then extracts the license-terms, de-serializes them and checks that the current software and date/time is within the terms on the license. Supplied is an example license file (valid until the year 9999) for user "Test" (Test.lic) - The public and private key files used to generate this license are also included.

This is the validateLicense method:

/// validate the user-license.
internal static bool validateLicenseFile()
{
    try
    {
        // reserve a license object:
        License license = null;

        // get the public key from internal resource:
        String publicKey = Properties.Resources.publicKey;

        // work out the expected license file-name:
        String licenseFile = Application.LocalUserAppDataPath + "\\" + 
					Environment.UserName + "_user.lic";

        // does the license file exist?
        if (File.Exists(licenseFile))
        {
            // load the license:
            license = License.Load(licenseFile);
        }
        else
        {
            // prompt the user for a license file:
            OpenFileDialog dlg = new OpenFileDialog();
    
            // setup a dialog;
            dlg.Filter = "User License Files (*.lic)|*.lic";
            dlg.Title = "Select License File";

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    // copy the license file into the local app data directory:
                    File.Copy(dlg.FileName, licenseFile);
 
                    // if it made it here, load it:
                    if (File.Exists(licenseFile))
                    {
                        license = License.Load(licenseFile);
                    }
                }
                catch
                {
                    // can't copy the file?.. load the original:
                    license = License.Load(dlg.FileName);
                }
            }
        }
        if (license != null)
        {
            // validate the signature on the license with the message contents, 
            // and the public key:
            LicenseAuthorization.ValidateLicense(license, publicKey);
       
            // if we get here, the license is valid;
            return true;
        }
        else
        {
            // no license file...
            MessageBox.Show("License File Not Supplied!", "License Check");
            return false;
        }
    }
    catch (SecurityException se)
    {
        // display the reason for the license check failure:
        MessageBox.Show(se.Message, "License Check");
    }

    // return false...invalid license.
    return false;
    }
}

Points of Interest

Something I discovered while doing the research for this: You can convert an array of bytes to a printable string using Convert.ToBase64String(). The result string always contains printable ASCII characters, and it is definitely not human-readable. The LicenseTerms class for this article, (which contains the start date, end date, product name, user name, etc.) is stored in the license file (which is XML) as a string. The string is created by serializing the licence-terms class to a byte-array using the binary-formatter. This doesn't encrypt the license terms by any means, but it makes it much harder to read, and it also makes it easy to deal with (no special serialization is required to save a string).

History

  • Version 1.0

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Simon Bridge
Technical Lead Evolution Management Consulting
Australia Australia
Wrote his first computer game in Microsoft Basic, on a Dragon 32 at age 7. It wasn't very good.
Has been working as a consultant and developer for the last 15 years,
Discovered C# a few years ago and hasn't looked back.
Feels wierd talking about himself in the third person.

Comments and Discussions

 
QuestionThanks - one question! PinmemberBreandan201322-Jun-14 16:59 
QuestionLicense generator Pinmemberbluexp200427-Feb-14 21:13 
QuestionRSA vs DSA Pinmemberjeffdavis870317-Dec-13 15:52 
QuestionThanks for the code.. Pinmemberbonny m koodathil19-Nov-13 21:12 
AnswerRe: Thanks for the code.. PinmemberSchattenMann28-Nov-13 3:00 
GeneralMy vote of 5 PinmemberJulioNobre4-Jul-13 4:43 
QuestionHow can I do if someone update the machine date to prolong license date? Pinmemberwngsheng25-Jan-13 22:58 
AnswerRe: How can I do if someone update the machine date to prolong license date? Pinmemberloulou_7501627-Mar-13 3:28 
GeneralMy vote of 5 PinmemberEdo Tzumer22-Jan-13 22:25 
QuestionMy vote of 5 Pinmembertessers29-Dec-12 7:34 
AnswerRe: My vote of 5 Pinmembertessers30-Dec-12 10:26 
GeneralMy vote of 5 PinmemberAkram El Assas29-Feb-12 23:58 
GeneralMy vote of 5 PinmemberPatrick Harris29-Feb-12 3:33 
QuestionWorks like magic . Thanks. but can it be simpler PinmemberMember 228177112-Nov-11 8:46 
AnswerRe: Works like magic . Thanks. but can it be simpler PinmemberMember 228177113-Nov-11 10:22 
GeneralRe: Works like magic . Thanks. but can it be simpler PinmemberSimon Bridge13-Nov-11 18:46 
QuestionPossible? Pinmembershelby6719-Aug-11 12:58 
AnswerRe: Possible? Pinmembershelby6719-Aug-11 13:00 
GeneralRe: Possible? PinmemberSimon Bridge19-Aug-11 15:34 
GeneralRe: Possible? Pinmembershelby6721-Aug-11 12:17 
AnswerRe: Possible? PinmemberSimon Bridge19-Aug-11 15:24 
GeneralRe: Possible? Pinmembershelby6721-Aug-11 12:16 
GeneralRe: Possible? PinmemberSimon Bridge21-Aug-11 15:09 
GeneralRe: Possible? Pinmemberpiero_goku29-Sep-12 7:10 
GeneralRe: Possible? PinmemberSimon Bridge1-Oct-12 18:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 30 May 2011
Article Copyright 2011 by Simon Bridge
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid