Adding Custom Data with Licence Info

Nov 30, 2012 at 12:41 PM
Edited Nov 30, 2012 at 12:42 PM

Hi,

I would like to add some custom info with Licence info, like Trial days is already there, but I want to use Number of user with Licence info, so my app can restrict the more users using the application. This is business requirement.

Please suggest me where I should change to add custom fields in Licence Info.

Thanks in advance.

Kishore

Dec 3, 2012 at 11:57 AM
Edited Dec 3, 2012 at 11:58 AM

Hi Alvaroma,
This tool is really cool, and could help me a lot more. As per my requirement I need to change the source to ful fill my requirement.

Details are as below :-
I have modified ProductKeyInfo Class as below to ful fill my business specific requirement.

 

namespace Activatar.Server
{
    public class ProductKeyInfo
    {
        public short ProductID { get; set; }

        public short ProductFeatures { get; set; }

        public short TrialDays { get; set; }

        public DateTime GeneratedDate { get; set; }

        //**************KKB Modified **************************/
        public string ProductEdition { get; set; }

        public string ClientId { get; set; }

        public short NoOfConnection { get; set; }

        /*****************************************************/
    }
}

 

Modified ActivateProduct and ValidateProductKey method in Activatar.Server as below

 

public ProductLicenseInfo ActivateProduct(string productKey, string machineHash)
        {
            try
            {
                ProductKeyPublisher keyPublisher = new ProductKeyPublisher(_cryptoService);
                ProductKeyInfo productInfo = keyPublisher.ValidateProductKey(productKey);

                byte[] proid = BitConverter.GetBytes(productInfo.ProductID);
                byte[] pinfo = BitConverter.GetBytes(productInfo.ProductFeatures);
                byte[] xinfo = BitConverter.GetBytes(productInfo.TrialDays);
                byte[] ticks = BitConverter.GetBytes(productInfo.GeneratedDate.Ticks);
                byte[] activ = BitConverter.GetBytes(DateTime.Now.Ticks);
                byte[] ediinfo = System.Text.Encoding.ASCII.GetBytes(productInfo.ProductEdition);
                byte[] clinfo = System.Text.Encoding.ASCII.GetBytes(productInfo.ClientId);
                byte[] ninfo = BitConverter.GetBytes(productInfo.NoOfConnection);
                byte[] mhash = Convert.FromBase64String(machineHash);

                byte[] infoBytes;
                using (MemoryStream memStream = new MemoryStream())
                {
                    memStream.Write(proid, 0, 2);
                    memStream.Write(pinfo, 0, 2);
                    memStream.Write(xinfo, 0, 2);
                    memStream.Write(ticks, 0, 8);
                    memStream.Write(activ, 0, 8);
                    memStream.Write(mhash, 0, mhash.Length);
                    //*********************KKB Modified********************//
                    memStream.Write(ediinfo, 0, 13);
                    memStream.Write(clinfo, 0, 6);
                    memStream.Write(ninfo, 0, 2);
                    /*******************************************************/
                    infoBytes = memStream.ToArray();
                }

                byte[] signBytes = _cryptoService.SignData(infoBytes, new SHA1CryptoServiceProvider());

                ProductLicenseInfo licenseInfo = new ProductLicenseInfo()
                {
                    ActivationInfo = Convert.ToBase64String(infoBytes),
                    Signature = Convert.ToBase64String(signBytes)
                };

                return licenseInfo;
            }
            catch (Exception ex)
            {
                return new ProductLicenseInfo()
                {
                    ActivationInfo = ex.Message,
                    Signature = null
                };
            }
        }

 public ProductKeyInfo ValidateProductKey(string productKey)
        {
            if (String.IsNullOrEmpty(productKey))
                throw new ArgumentNullException("Product Key is null or empty.");

            if (productKey.Length != 35)
                throw new ArgumentException("Product key is invalid.");

            productKey = productKey.Replace("-", "");

            byte[] keyBytes = Base32Converter.FromBase32String(productKey);

            byte[] signBytes = new byte[2];
            byte[] hiddenBytes = new byte[16];
            using (MemoryStream stream = new MemoryStream(keyBytes))
            {
                stream.Read(hiddenBytes, 0, 8);
                stream.Read(signBytes, 0, 2);
                stream.Read(hiddenBytes, 8, hiddenBytes.Length - 8);
                keyBytes = stream.ToArray();
            }

            byte[] sign = _cryptoService.SignData(signBytes, new SHA1CryptoServiceProvider());
            byte[] rkey = new byte[32];
            byte[] rjiv = new byte[16];
            Array.Copy(sign, rkey, 32);
            Array.Copy(sign, 32, rjiv, 0, 16);

            SymmetricAlgorithm algorithm = new RijndaelManaged();
            byte[] hiddenData;
            try
            {
                hiddenData = algorithm.CreateDecryptor(rkey, rjiv).TransformFinalBlock(hiddenBytes, 0, hiddenBytes.Length);
            }
            catch (Exception ex)
            {
                throw new InvalidProductKeyException("Product key is invalid.", ex);
            }

            byte[] proid = new byte[2];
            byte[] pinfo = new byte[2];
            byte[] xinfo = new byte[2];
            byte[] ticks = new byte[8];

            using (MemoryStream memStream = new MemoryStream(hiddenData))
            {
                memStream.Read(proid, 0, 2);
                memStream.Read(pinfo, 0, 2);
                memStream.Read(xinfo, 0, 2);
                memStream.Read(ticks, 0, 8);
            }

            if (signBytes[0] == proid[0] && signBytes[1] == proid[1])
            {
                DateTime generatedDate = new DateTime(BitConverter.ToInt64(ticks, 0));
                if (generatedDate.Year > 2000 && generatedDate.Year < 2100)
                {
                    return new ProductKeyInfo()
                    {
                        ProductID = BitConverter.ToInt16(proid, 0),
                        ProductFeatures = BitConverter.ToInt16(pinfo, 0),
                        TrialDays = BitConverter.ToInt16(xinfo, 0),
                        GeneratedDate = generatedDate,
                        /**********************KKB Modified ***************/
                        ClientId = "SBO001", //programmatically change require
                        NoOfConnection = 2, //programmatically change require
                        ProductEdition = "02.03.00.0624" //programmatically change require
                        /**************************************************/
                    };
                }
                else
                {
                    throw new InvalidProductKeyException("Product key date is incorrect.");
                }
            }
            else
            {
                throw new InvalidProductKeyException("Product key info is incorrect.");
            }
        }

Now I modified ProcessLicence () method in Activatar Library as below:

 

 

 private void ProcessLincense()
        {
            try
            {
                byte[] dataBytes = Convert.FromBase64String(LicenseInfo.ActivationInfo);
                byte[] signBytes = Convert.FromBase64String(LicenseInfo.Signature);

                if (_cryptoService.VerifyData(dataBytes, new SHA1CryptoServiceProvider(), signBytes))
                {
                    int infoLength = 43; // ProductID (2) + ProductFeatures (2) + TrialDays (2) + CreationDate (8) + ActivationDate (8) + ProductEdition(13) + ClientId(6) + NoOfConnection(2)= 43
                    byte[] hash = new byte[dataBytes.Length - infoLength];
                    Buffer.BlockCopy(dataBytes, infoLength, hash, 0, hash.Length);
                    if (_identifierService.Match(hash))
                    {
                        ProductID = BitConverter.ToInt16(dataBytes, 0);
                        ProductFeatures = BitConverter.ToInt16(dataBytes, 2);
                        TrialDays = BitConverter.ToInt16(dataBytes, 4);
                        ProductKeyCreationDate = new DateTime(BitConverter.ToInt64(dataBytes, 6));
                        ActivationDate = new DateTime(BitConverter.ToInt64(dataBytes, 14));
                        //******************KKB Modified**************************/
                        //memStream.Write(ediinfo, 0, 13);
                        //memStream.Write(clinfo, 0, 6);
                        //memStream.Write(ninfo, 0, 2);
                        ProductEdition = System.Text.Encoding.ASCII.GetString(dataBytes, 15, 38);
                        ClientId = System.Text.Encoding.ASCII.GetString(dataBytes, 39, 45);
                        NoOfConnection = BitConverter.ToInt16(dataBytes, 46);
                        /*********************************************************/
                        if (TrialDays == 0)
                        {
                            Status = LicenseStatus.Licensed;
                            StatusReason = String.Empty;
                            TrialDaysLeft = Int32.MaxValue;
                        }
                        else
                        {
                            TrialDaysLeft = (TrialDays - (DateTime.Today - ActivationDate.Date).Days);
                            if (TrialDaysLeft > 0)
                            {
                                Status = LicenseStatus.TrialVersion;
                                StatusReason = String.Format("{0} days left.", TrialDaysLeft);
                            }
                            else
                            {
                                Status = LicenseStatus.Expired;
                                StatusReason = String.Format("License expired {0} days ago.", -TrialDaysLeft);
                            }
                        }
                    }
                    else
                    {
                        Status = LicenseStatus.MachineHashMismatch;
                        StatusReason = "Machine and product info hash mismatch.";
                    }
                }
                else
                {
                    Status = LicenseStatus.Invalid;
                    StatusReason = "Failed verifying signature.";
                }
            }
            catch (Exception ex)
            {
                Status = LicenseStatus.Invalid;
                StatusReason = ex.Message;
            }
        }

 

But I am getting error status as "StatusReason = "Machine and product info hash mismatch." and never satisfying  if (_identifierService.Match(hash))

Please help me where I am doing wrong, how can I fulfill my requirement. I need to send few more information as Licence Information to client, where client will compile and work as details.

Thanks

With Regards

Kishore  

Coordinator
Jan 25, 2013 at 11:10 PM

Hi Kishore,

I'm afraid you cannot easily add new data to the product key, unless you make the product key bigger in length. Note that the product key is just a representation of a hash of bytes (currently 22 bytes) containing the product information. If you need to store more information, (lets say 22 bytes more) the product key will result in the double of letters.

As a solution try to compact the information inside the 22 bytes. For instance, the two datetime values use 8 bytes each, while maybe 4 bytes will have accuracy enough.

On the other hand, the product key should include only required information about the product to be activated, while the license may include more information that can be added in the server after the activation. For example, the product key have information about WHAT product is it, WISH features and WHEN expire. In the server, with the product ID and features, a related information could be added to the license.

Hope this helps,

Alvaro