License for C# desktop application

I'm probably a bit late, but I spent a bit of time trying to work out a quick and effective method of securing a little C# application, and I would like to share my results.

It seems you can build your own, fairly secure licensing system using RSA reasonably easily.

Obviously, nothing is bullet-proof when it comes to protecting software (It's like protecting your house from burglars: alarms, barking dogs and fences make it more trouble than it's worth, but they won't stop someone determined to get in)

So, making it more trouble than it's worth is the key phrase in software protection: if you are offering a $1,000,000 E.R.P. system, you would want to have really good protection that authorized via a web-service (and users paying that much for a system would not have a problem with allowing that system constant internet access)

However, if you are charging only $5-$30 for a little app, users are not going to put up with very heavy handed authorization.

I think the simplest system to produce is to digitally sign a license-file that contains the details of product, the user and it's duration.

This means any modification of the license file makes the digital signature invalid.

The digital signature can be obtained from the DSACryptoServiceProvider class, using the SignData method.

A private key is required to sign the data, and the public part of that key can be used to validate the signature: (thus the public key must be accessible by the application)

The DSAXCryptoServiceProvider has methods for creating and using keys:

DSACryptoServiceProvider.ToXMLString(bool includePrivate);

returns the Public or Public & Private keys currently in the service provider as an XML string.

DSACryptoServiceProvider.FromXMLString(String xmlString)

This method sets up a new DSACryptoServiceProvider with existing private or public keys obtained from DSACryptoServiceProvider.ToXMLString()

The only flaw in the security of this system would be the possibility of a user breaking in an supplying their own public-key. This would allow them to generate their own license files from their own private-key.

This can be gotten around by additionally signing a required resource for the application (like a .dll that contains essential logic for the application, or even the .exe itself) - thus if the public key is changed, this additional (hidden) signature will become invalid.

Other ways to improve this include obscuring the license terms (serializing a data-structure containing the license terms using the binary-formatter to a byte array, then using Convert.ToBase64String() will quite effectively obscure the licensing terms, and even if the user was able to replace the public-key they would still need to work out the representation of the data)

I have an example system I wrote, but it is too big to quote entirely, but this is the CreateLicense method from it:

    /// <summary>
    /// use a private key to generate a secure license file. the private key must match the public key accessible to
    /// the system validating the license.
    /// </summary>
    /// <param name="start">applicable start date for the license file.</param>
    /// <param name="end">applicable end date for the license file</param>
    /// <param name="productName">applicable product name</param>
    /// <param name="userName">user-name</param>
    /// <param name="privateKey">the private key (in XML form)</param>
    /// <returns>secure, public license, validated with the public part of the key</returns>
    public static License CreateLicense(DateTime start, DateTime end, String productName, String userName, String privateKey)
    {
        // create the licence terms:
        LicenseTerms terms = new LicenseTerms()
        {
            StartDate = start,
            EndDate = end,
            ProductName = productName,
            UserName = userName
        };

        // create the crypto-service provider:
        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();

        // setup the dsa from the private key:
        dsa.FromXmlString(privateKey);

        // get the byte-array of the licence terms:
        byte[] license = terms.GetLicenseData();

        // get the signature:
        byte[] signature = dsa.SignData(license);

        // now create the license object:
        return new License()
        {
            LicenseTerms = Convert.ToBase64String(license),
            Signature = Convert.ToBase64String(signature)
        };
    }

Verify Method:

    /// <summary>
    /// validate license file and return the license terms.
    /// </summary>
    /// <param name="license"></param>
    /// <param name="publicKey"></param>
    /// <returns></returns>
    internal static LicenseTerms GetValidTerms(License license, String publicKey)
    {
        // create the crypto-service provider:
        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();

        // setup the provider from the public key:
        dsa.FromXmlString(publicKey);

        // get the license terms data:
        byte[] terms = Convert.FromBase64String(license.LicenseTerms);

        // get the signature data:
        byte[] signature = Convert.FromBase64String(license.Signature);

        // verify that the license-terms match the signature data
        if (dsa.VerifyData(terms, signature))
            return LicenseTerms.FromString(license.LicenseTerms);
        else
            throw new SecurityException("Signature Not Verified!");
    }

The License Terms Class:

    /// <summary>
    /// terms of the license agreement: it's not encrypted (but is obscured)
    /// </summary>
    [Serializable]
    internal class LicenseTerms
    {
        /// <summary>
        /// start date of the license agreement.
        /// </summary>
        public DateTime StartDate { get; set; }

        /// <summary>
        /// registered user name for the license agreement.
        /// </summary>
        public String UserName { get; set; }

        /// <summary>
        /// the assembly name of the product that is licensed.
        /// </summary>
        public String ProductName { get; set; }

        /// <summary>
        /// the last date on which the software can be used on this license.
        /// </summary>
        public DateTime EndDate { get; set; }

        /// <summary>
        /// returns the license terms as an obscure (not human readable) string.
        /// </summary>
        /// <returns></returns>
        public String GetLicenseString()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-steam;
                bnfmt.Serialize(ms, this);

                // return a base64 string representation of the binary data:
                return Convert.ToBase64String(ms.GetBuffer());

            }
        }

        /// <summary>
        /// returns a binary representation of the license terms.
        /// </summary>
        /// <returns></returns>
        public byte[] GetLicenseData()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-steam;
                bnfmt.Serialize(ms, this);

                // return a base64 string representation of the binary data:
                return ms.GetBuffer();

            }
        }

        /// <summary>
        /// create a new license-terms object from a string-representation of the binary
        /// serialization of the licence-terms.
        /// </summary>
        /// <param name="licenseTerms"></param>
        /// <returns></returns>
        internal static LicenseTerms FromString(String licenseTerms)
        {

            using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(licenseTerms)))
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-steam;
                object value = bnfmt.Deserialize(ms);

                if (value is LicenseTerms)
                    return (LicenseTerms)value;
                else
                    throw new ApplicationException("Invalid Type!");

            }
        }

    }

There are plenty of license management systems out there for .NET (there's even one built-in for licensing controls). A quick Google around for ".NET licence manager" threw up the Open License system, which is free.

I expect you can easily find more.


I thought it would be worth adding another answer to this as the accepted answer seems to reference a project that is not currently maintained.

I would recommend looking at Standard.Licensing, which is a free, open-source licensing library for .Net that works with the .Net Framework, Mono, .Net Core, .Net Standard and Xamarin. Is modernises the older Portable.Licensing by adding support for newer platforms, specifically .Net Core and .Net Standard.

Standard.Licensing works by creating a digitally signed XML file that contains information relevant to your product, such as the type of the product and the expiry date. The fact that the XML file has not been changed can be verified when you check the licence and your application can then trust the claims made in the licence file. (Note that you might want to also verify that the computer's clock is accurate to prevent someone just changing the date.)

Standard.Licensing signs the XML file using the Elliptic Curve Digital Signature Algorithm (ECDSA) algorithm, which uses a pair of keys, one public and one private when creating the licence file. You only need to use the public key to decrypt and verify the licence. As it is not possible to use just the public key to modify the licence file, you can just safely include the public with your application and you do not need to resort to approaches such as obfuscating your assembly to prevent people from seeing the public key. Note that this is similar to the approach mentioned in Simon Bridge's answer above.

Standard.Licensing has a fluent API that you use to create and verify the licences. Here's the snippet from their website showing how to create a licence:

var license = License.New()  
    .WithUniqueIdentifier(Guid.NewGuid())  
    .As(LicenseType.Trial)  
    .ExpiresAt(DateTime.Now.AddDays(30))  
    .WithMaximumUtilization(5)  
    .WithProductFeatures(new Dictionary<string, string>  
        {  
            {"Sales Module", "yes"},  
            {"Purchase Module", "yes"},  
            {"Maximum Transactions", "10000"}  
        })  
    .LicensedTo("John Doe", "[email protected]")  
    .CreateAndSignWithPrivateKey(privateKey, passPhrase);

In your application, you then load and validate the licence file:

using Standard.Licensing.Validation;

var license = License.Load(...);
var validationFailures = license.Validate()  
                                .ExpirationDate()  
                                .When(lic => lic.Type == LicenseType.Trial)  
                                .And()  
                                .Signature(publicKey)  
                                .AssertValidLicense();