Using SSH Keys for License generation and validation in .NET Applications

license_generationpng

 

This blog post is going to present how can you implement license functionality in your .NET application. Providing license in your .NET application is very challenging because there is no standard procedure for the implementation. You are free to use whatever you want. But be notice, there is no license which is 100% safe and cannot be cracked or bypassed.

For this purpose I have selected the CocoaFob library for registration code generation and verification in Objective-C applications. Mainly the library is for Objective -C based applications, like iQS mobile applications and other OSX based applications. This is very interesting library but you cannot use it in .NET applications, there is no implementation for .NET Framework.

The library uses DSA to generate registration keys, which is very hard for hackers to produce key generators. The library is also specific because it generates license key in human readable form, when the bytes are converted in to Base32 string to avoid ambiguous characters. It also groups codes in sets of five characters separated by dashes. Also DSA has encryption algorithm generates the license which is different every time because of a random element introduced during the process.

So the License key is produced using a 512-bit DSA key looks like on the following sample:

GAWQE-FCUGU-7Z5JE-WEVRA-PSGEQ-Y25KX-9ZJQQ-GJTQC-CUAJL-ATBR9-WV887-8KAJM-QK7DT-EZHXJ-CR99C-A

More information about CocoaFob can be found at GitHub page: https://github.com/glebd/cocoafob

The library is using BouncyCastle.Crypto Nuget package for DSA encryption and decryption.

The library CocoaFob for .NET contains two classes:

  1. LicenseData class which provide License properties which is used in license generation. It an be anything: Name, Product number, email, date of expiration etc.
  2. LicenseGenerator class which is responsible for encrypting and validating the license.

For this blog post the License data class has the flowing implementation:

public class LicenseData
    {

        protected internal string productCode;
        protected internal string name;
        protected internal string email;

        /// <summary>
        /// Returns the string data input for the CocoaFob algorithm. This implementation returns a comma separated string
        /// including the <seealso cref="#productCode"/>, <seealso cref="#name"/> and <seealso cref="#email"/> if set.
        /// @return
        /// </summary>
        public virtual string toLicenseStringData()
        {
            StringBuilder result = new StringBuilder();
            if (productCode != null)
            {
                result.Append(productCode);
                result.Append(',');
            }

            //name is mandatory property
            if (name == null)
                throw new System.Exception("name cannot be null");
            result.Append(name);

            if (email != null)
            {
                result.Append(',');
                result.Append(email);
            }
            return result.ToString();
        }
...
}

As can be seen from the code snippet above the License data contains username, product key and email address. Also, only name property is mandatory, which means you can generate license key based on the user name only.

Generating the License Key

One we have License data we can process of License key generation. License is generated using DSA encryption which uses SSH private key. You can generate public and private SSH keys using any of the available tools, eg. OpenSSH, GitHub bash, .... More information about private and public key generation you can find at this link. Once we have public and private keys we can generate license and validate it. One important thing to remember is that you have to care about your private key. It should always be secure and no one should have access to it.

The public key is used for license validation, and it is usualy packed with the application as a part of the deployment stuff. So the process of generating the license is show on the flowing code snippet:

public string makeLicense(LicenseData licenseData)
{
    if (!CanMakeLicenses)
    {
        throw new System.InvalidOperationException("The LicenseGenerator cannot make licenses as it was not configured with a private key");
    }
    try
    {
        //
        var dsa = SignerUtilities.GetSigner("SHA1withDSA");
        dsa.Init(true, privateKey);

        //
        string stringData = licenseData.toLicenseStringData();
        byte[] licBytes = Encoding.UTF8.GetBytes(stringData);
        dsa.BlockUpdate(licBytes, 0, licBytes.Length);

        //
        byte[] signed = dsa.GenerateSignature();


        string license = ToLicenseKey(signed);


        return license;
    }
    catch (Exception e)
    {
        throw new LicenseGeneratorException(e);
    }
}

First the DSA encryption is created based on the publicKey we have provided as an argument. Then licBytes is generated from the License data, and converted in to UTF8 formatted bytes. Then we have update DSA provider with licBytes. Now the DSA provider can generate signature in bytes. The signature is converted in to LicenseKey by calling ToLicenseKey method. The method is shown on the following code snippet:

private string ToLicenseKey(byte[] signature)
        {
            /* base 32 encode the signature */
            var result = Base32.ToString(signature);

            /* replace O with 8 and I with 9 */
            result = result.Replace("O", "8").Replace("I", "9");

            /* remove padding if any. */
            result = result.Replace("=", "");
           

            /* chunk with dashes */
            result = split(result, 5);
            return result;
        }

The magic happen in this method during the conversion of signature from bytes to human readable string. Conversion is done using Base32 string helper method.

Verify the License Key

The License verification process is defined in varifyLicense method. You have to provide SSH publicKey as well as

        public virtual bool verifyLicense(LicenseData licenseData, string license)
        {
            if (!CanVerifyLicenses)
            {
                throw new System.InvalidOperationException("The LicenseGenerator cannot verify licenses as it was not configured with a public key");
            }
            try
            {
                //Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
                var dsa = SignerUtilities.GetSigner("SHA1withDSA");
                dsa.Init(false, publicKey);

                //
                string stringData = licenseData.toLicenseStringData();
                byte[] msgBytes = Encoding.UTF8.GetBytes(stringData);
                dsa.BlockUpdate(msgBytes, 0, msgBytes.Length);


                var dec = FromLicenseKey(license);
                var retVal = dsa.VerifySignature(dec);
                //
                return retVal;
            }
            catch (Exception e)
            {
                throw new LicenseGeneratorException(e);
            }
        }

As can be seen from the code above, the validation process is done by generating licenseData, converting the license Key in to signatere and the validation process return true is the license is valid, otherwize return false.

The whole project is published at git hub, an can be downloaded from http://github.com/bhrnjica/cocoafob

 

Testing the Library

The Library solution contains unit test project which you can see how to use this library in the real scenario in order to implement licensing in .NET app.

Happy programming!


Posted Dec 06 2016, 06:37 PM by Bahrudin
developers.de is a .Net Community Blog powered by daenet GmbH.