static void Main(string[] args)
        {
            // In this sample, we will use the user id as our seed. This could be any integer that you can retrive in the future,
            // such as application id or even a combination of user id and application id

            Console.WriteLine("Please enter a dummy user id (integer). This will be used as our seed:");

            int userId = int.Parse(Console.ReadLine());

            // We will use the LicenceServer project in this sample to generate a key.
            // In production code, the licence server mechanism would be a separate application
            // from the application that verifies the key. This is important so as to protect the
            // full KeyByteSet array that was used to generate the key.

            var licenceServer = new LicenceServer();

            // Generate the licence key using the seed

            string licenceKeyStr = licenceServer.GenerateLicenceKey(userId);

            Console.WriteLine("\nLicence key generated: " + licenceKeyStr);
            Console.WriteLine("\nNow we will verify the licence key. Please type the licence key printed above: ");

            var result = PkvLicenceKeyResult.KeyInvalid;

            while (result != PkvLicenceKeyResult.KeyGood)
            {
                string userEnteredLicenceKeyStr = Console.ReadLine();

                var pkvKeyCheck = new PkvKeyCheck();

                // Here we recreate a subset of the full original KeyByteSet array that
                // was used to create the licence key. Note the argument to keyByteNo in 
                // each matches that in the full KeyByteSet array.

                var keyBytes = new[] {

                    new KeyByteSet(5, 165, 15, 132), 
                    new KeyByteSet(6, 128, 175, 213)
                };

                result = pkvKeyCheck.CheckKey(userEnteredLicenceKeyStr, keyBytes, 8, null);

                if (result != PkvLicenceKeyResult.KeyGood)
                {
                    Console.WriteLine("\nResult is: " + result.ToString() + ". Please try again.");
                }
            }

            Console.WriteLine("\nResult is: " + result.ToString() + ". Press any key to exit.");
            Console.ReadKey();
        }
        /// <summary>
        /// Check activation key file for valid licence key or trial period value
        /// </summary>
        /// <param name="activationKeyFileFullPath">The absolute local path where the activation key file exists</param>
        /// <param name="keyByteSet2"> </param>
        /// <param name="licenceKeyFileEncryptionString">An encryption key which the licence key XML will be decrypted with</param>
        /// <param name="friendlyApplicationName">A friendly application name for error reporting e.g. 'My Licenced Application'</param>
        /// <param name="keyByteSet1"> </param>
        public void CheckActivationKeyFile(string activationKeyFileFullPath, KeyByteSet keyByteSet1, KeyByteSet keyByteSet2, string licenceKeyFileEncryptionString, string friendlyApplicationName)
        {
            if (!File.Exists(activationKeyFileFullPath))
            {
                throw new ActivationKeyFileNotPresentException("The product activation key file '" + activationKeyFileFullPath + "' was expected at '" + activationKeyFileFullPath + "', but was not found. Please visit the vendor website to obtain a product activation key file.");
            }

            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(activationKeyFileFullPath);

            XmlNodeList activationCodeEncrypted = xmlDoc.GetElementsByTagName("Key");

            var activationKeyEncrypted = activationCodeEncrypted[0].InnerText;

            if (!String.IsNullOrEmpty(activationKeyEncrypted))
            {
                string clearTextActivationKey = String.Empty;

                try
                {
                    clearTextActivationKey = ActivationKeyDecryption.Decrypt(activationKeyEncrypted, licenceKeyFileEncryptionString);
                }
                catch
                {
                    throw new ActivationKeyInvalidException(string.Format("The licence key that allows {0} to run is invalid. Please check that the key file exists in the executing directory, and has not been modified.", friendlyApplicationName));
                }

                // If a check is made, that means that the free trial build period has expired

                if (clearTextActivationKey.ToLower() == "trial")
                {
                    throw new TrialPeriodExpiredException(string.Format("The trial period for {0} has expired.", friendlyApplicationName));
                }

                var pkvLicenceKeyResult = new PkvKeyCheck().CheckKey(clearTextActivationKey, new [] { keyByteSet1, keyByteSet2 }, 8, null);

                if (pkvLicenceKeyResult != PkvLicenceKeyResult.KeyGood)
                {
                    throw new ActivationKeyInvalidException(string.Format("The licence key that allows {0} to run is invalid. Please check that the key file exists in the executing directory, and has not been modified.", friendlyApplicationName));
                }
            }
        }
        /// <summary>
        /// Check activation key file for valid licence key or trial period value
        /// </summary>
        /// <param name="activationKeyFileFullPath">The absolute local path where the activation key file exists</param>
        /// <param name="keyByteSet2"> </param>
        /// <param name="licenceKeyFileEncryptionString">An encryption key which the licence key XML will be decrypted with</param>
        /// <param name="friendlyApplicationName">A friendly application name for error reporting e.g. 'My Licenced Application'</param>
        /// <param name="keyByteSet1"> </param>
        public void CheckActivationKeyFile(string activationKeyFileFullPath, KeyByteSet keyByteSet1, KeyByteSet keyByteSet2, string licenceKeyFileEncryptionString, string friendlyApplicationName)
        {
            if (!File.Exists(activationKeyFileFullPath))
            {
                throw new ActivationKeyFileNotPresentException("The product activation key file '" + activationKeyFileFullPath + "' was expected at '" + activationKeyFileFullPath + "', but was not found. Please visit the vendor website to obtain a product activation key file.");
            }

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(activationKeyFileFullPath);

            XmlNodeList activationCodeEncrypted = xmlDoc.GetElementsByTagName("Key");

            var activationKeyEncrypted = activationCodeEncrypted[0].InnerText;

            if (!String.IsNullOrEmpty(activationKeyEncrypted))
            {
                string clearTextActivationKey = String.Empty;

                try
                {
                    clearTextActivationKey = ActivationKeyDecryption.Decrypt(activationKeyEncrypted, licenceKeyFileEncryptionString);
                }
                catch
                {
                    throw new ActivationKeyInvalidException(string.Format("The licence key that allows {0} to run is invalid. Please check that the key file exists in the executing directory, and has not been modified.", friendlyApplicationName));
                }

                // If a check is made, that means that the free trial build period has expired

                if(clearTextActivationKey.ToLower() == "trial")
                {
                    throw new TrialPeriodExpiredException(string.Format("The trial period for {0} has expired.", friendlyApplicationName));
                }

                var pkvLicenceKeyResult = new PkvKeyCheck().CheckKey(clearTextActivationKey, new [] { keyByteSet1, keyByteSet2 }, 8, null);

                if (pkvLicenceKeyResult != PkvLicenceKeyResult.KeyGood)
                {
                    throw new ActivationKeyInvalidException(string.Format("The licence key that allows {0} to run is invalid. Please check that the key file exists in the executing directory, and has not been modified.", friendlyApplicationName));
                }
            }
        }
        public void Test_pkv_licence_key_generation_and_verification()
        {
            var pkvLicenceKey = new PkvLicenceKeyGenerator();

            var pkvKeyCheck = new PkvKeyCheck();

            string key = String.Empty;

            KeyByteSet[] keyByteSets = new []
                                               {
                                                   new KeyByteSet(1, 58, 6, 97),
                                                   new KeyByteSet(2, 96, 254, 23),
                                                   new KeyByteSet(3, 11, 185, 69), 
                                                   new KeyByteSet(4, 2, 93, 41),
                                                   new KeyByteSet(5, 62, 4, 234),
                                                   new KeyByteSet(6, 200, 56, 49), 
                                                   new KeyByteSet(7, 89, 45,142), 
                                                   new KeyByteSet(8, 6, 88, 32)
                                               };

            // Change these to a random key byte set from the above array to test key verification with

            KeyByteSet kbs1 = keyByteSets[3];
            KeyByteSet kbs2 = keyByteSets[7];
            KeyByteSet kbs3 = keyByteSets[4];

            // The check project also uses a class called KeyByteSet, but with
            // separate name spacing to achieve single self contained dll

            KeyByteSet keyByteSet1 = new KeyByteSet(kbs1.KeyByteNo, kbs1.KeyByteA, kbs1.KeyByteB, kbs1.KeyByteC); // Change no to test others
            KeyByteSet keyByteSet2 = new KeyByteSet(kbs2.KeyByteNo, kbs2.KeyByteA, kbs2.KeyByteB, kbs2.KeyByteC);
            KeyByteSet keyByteSet3 = new KeyByteSet(kbs3.KeyByteNo, kbs3.KeyByteA, kbs3.KeyByteB, kbs3.KeyByteC);

            for (int i = 0; i < 10000; i++)
            {
                int seed = new Random().Next(0, Int32.MaxValue);

                key = pkvLicenceKey.MakeKey(seed, keyByteSets);

                // Check that check sum validation passes

                Assert.True(pkvKeyCheck.CheckKeyChecksum(key, keyByteSets.Length));

                // Check using full check method

                Assert.True(pkvKeyCheck.CheckKey(
                                            key,
                                            new[] { keyByteSet1, keyByteSet2, keyByteSet3 },
                                            keyByteSets.Length,
                                            null
                                        ) == PkvLicenceKeyResult.KeyGood, "Failed on iteration " + i
                            );

                // Check that erroneous check sum validation fails

                Assert.False(pkvKeyCheck.CheckKeyChecksum(key.Remove(23, 1) + "A", keyByteSets.Length)); // Change key by replacing 17th char
            }

            // Check a few random inputs

            Assert.False(pkvKeyCheck.CheckKey("adcsadrewf",
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null) == PkvLicenceKeyResult.KeyGood
                        );
            Assert.False(pkvKeyCheck.CheckKey("",
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null) == PkvLicenceKeyResult.KeyGood
                        );
            Assert.False(pkvKeyCheck.CheckKey("123",
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null) == PkvLicenceKeyResult.KeyGood
                        );
            Assert.False(pkvKeyCheck.CheckKey("*()",
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null) == PkvLicenceKeyResult.KeyGood
                        );
            Assert.False(pkvKeyCheck.CheckKey("dasdasdasgdjwqidqiwd21887127eqwdaishxckjsabcxjkabskdcbq2e81y12e8712",
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null) == PkvLicenceKeyResult.KeyGood
                        );
        }
        public void Test_PKV_licence_key_generation_and_verification_with_random_key_bytes_key_byte_qty_and_verification_key_byte_selection()
        {
            var pkvLicenceKey = new PkvLicenceKeyGenerator();

            var pkvKeyCheck = new PkvKeyCheck();

            for (int i = 0; i < 10000; i++)
            {
                int randomKeyByteSetsLength = new Random().Next(2, 400);

                KeyByteSet[] keyByteSets = new KeyByteSet[randomKeyByteSetsLength];

                for (int j = 0; j < randomKeyByteSetsLength; j++)
                {
                    var random = new Random();

                    var kbs = new KeyByteSet
                                  (
                                      j + 1,
                                      (byte)random.Next(0, 256),
                                      (byte)random.Next(0, 256),
                                      (byte)random.Next(0, 256)
                                  );

                    keyByteSets[j] = kbs;
                }

                // Select a random key byte set to test key verification with

                KeyByteSet kbs1 = keyByteSets[new Random().Next(0, randomKeyByteSetsLength)];
                KeyByteSet kbs2 = keyByteSets[new Random().Next(0, randomKeyByteSetsLength)];

                // The check project also uses a class called KeyByteSet, but with
                // separate name spacing to achieve single self contained dll

                KeyByteSet keyByteSet1 = new KeyByteSet(kbs1.KeyByteNo, kbs1.KeyByteA, kbs1.KeyByteB, kbs1.KeyByteC); // Change no to test others
                KeyByteSet keyByteSet2 = new KeyByteSet(kbs2.KeyByteNo, kbs2.KeyByteA, kbs2.KeyByteB, kbs2.KeyByteC);

                int seed = new Random().Next(0, Int32.MaxValue);

                string key = pkvLicenceKey.MakeKey(seed, keyByteSets);

                // Check that check sum validation passes

                Assert.True(pkvKeyCheck.CheckKeyChecksum(key, keyByteSets.Length));

                // Check using full check method

                Assert.True(pkvKeyCheck.CheckKey(
                                            key,
                                            new[] { keyByteSet1, keyByteSet2 },
                                            keyByteSets.Length,
                                            null
                                        ) == PkvLicenceKeyResult.KeyGood, "Failed on iteration " + i
                            );

            }
        }