Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Windows Forms
Article

RSA License Protection

Rate me:
Please Sign up or sign in to vote.
4.93/5 (41 votes)
30 May 2011CPOL7 min read 160K   11.4K   180   62
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:

C#
/// 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)


Written By
Software Developer (Senior) Decipha
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# shortly after it was created, and hasn't looked back.
Feels weird talking about himself in the third person.

Comments and Discussions

 
GeneralRe: The problem Pin
Simon Bridge8-Jun-11 14:24
Simon Bridge8-Jun-11 14:24 
GeneralRe: The problem Pin
Simon Bridge8-Jun-11 15:05
Simon Bridge8-Jun-11 15:05 
GeneralRe: The problem Pin
Bill Seddon8-Jun-11 15:51
Bill Seddon8-Jun-11 15:51 
GeneralRe: The problem Pin
Simon Bridge8-Jun-11 17:01
Simon Bridge8-Jun-11 17:01 
GeneralRe: The problem Pin
Bill Seddon8-Jun-11 23:00
Bill Seddon8-Jun-11 23:00 
GeneralRe: The problem Pin
Simon Bridge9-Jun-11 14:09
Simon Bridge9-Jun-11 14:09 
GeneralRe: The problem Pin
Member 87381511-Jun-11 9:07
Member 87381511-Jun-11 9:07 
QuestionRe: The problem Pin
Simon Bridge9-Jun-11 17:52
Simon Bridge9-Jun-11 17:52 
Bill,

Do you know if anyone has broken the click-once manifest file security? As far as I can tell, it digitally signs the executable, and won't allow it to run if the signatures don't match.

I know Microsoft isn't famed for it's security, but they have a lot of resources and presumably put a lot of effort into making it secure.
AnswerRe: The problem Pin
Bill Seddon10-Jun-11 0:24
Bill Seddon10-Jun-11 0:24 
QuestionRhino-Licensing Pin
Giorgi Dalakishvili4-Jun-11 7:02
mentorGiorgi Dalakishvili4-Jun-11 7:02 
AnswerRe: Rhino-Licensing [modified] Pin
Simon Bridge8-Jun-11 17:40
Simon Bridge8-Jun-11 17:40 
GeneralRe: Rhino-Licensing Pin
Giorgi Dalakishvili8-Jun-11 21:16
mentorGiorgi Dalakishvili8-Jun-11 21:16 
GeneralMy vote of 5 Pin
Aron Weiler3-Jun-11 11:45
Aron Weiler3-Jun-11 11:45 
Generalmy vote of 5 Pin
Southmountain30-May-11 7:27
Southmountain30-May-11 7:27 
GeneralRe: my vote of 5 Pin
Simon Bridge30-May-11 14:09
Simon Bridge30-May-11 14:09 
GeneralRe: my vote of 5 Pin
Member 233046430-May-11 18:47
Member 233046430-May-11 18:47 
GeneralMy vote of 5 Pin
Filip D'haene30-May-11 6:41
Filip D'haene30-May-11 6:41 

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

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