An easy way to add license file support to your .Net application

    Some time ago, a friend asked me to automate part of the routine work of his business. At that moment I was looking forward to the coming reduction and agreed with pleasure.
    The development took three full cycles and now the fourth final cycle of work on the program is coming to an end and I had the idea to move my product further to the masses. It is said that it was done, work began on drafting contracts, design changes, otbutforsingu and other other craps and the most interesting question arose - how to protect the program from non-licensed use and prevent just copying it?

    After browsing the Internet, more precisely through the CodeProject portal , I found several implementations using license files.
    In theory, the problem is solved simply:
    1. Create an xml file with the content we need
    2. Signing a file using the SignedXml class
    3. In the application, we verify the signature. If the check is successful - we look at the contents of the file, if not - we immediately get an error

    In practice, the SignedXml object requires an instance of AssimetricAlgorithm encryption. In the examples found, asymmetric encryption was used by any certificate installed on the computer and then decrypted by the exported public key. Considering that after some time I am going to reinstall the system, I had to bother with exporting the certificate, and it’s not an option that it can then get back at all, and there’s a very long implementation code.
    I thought, because it might be easier. And found it.
    All the work of the Subscriber is to add to the xml a certain string that must be checked. So why don’t I write there my line formed by a certain algorithm. My method uses a symmetric encryption method, so to speak.
    I needed to check whether the license had expired, by which date it is possible to receive updates, and who actually owns this license.
    I created two classes: one for creating a license file, the other for checking it.
    The method is very simple. We take the input parameters for creating the license, write everything in xml. Then concatenate these very parameters, add some constant to them, get a hash, which will be our signature, and append it to the end of xml in the corresponding section.

    class LicenseGenerator
      {
        public void Generate(string Path,String Name, DateTime StartDate, DateTime UpdateTo)
        {

          XmlDocument doc = new XmlDocument();
          doc.LoadXml(@"
                
                
                
                
                
    ");
          doc.ChildNodes[0].SelectSingleNode(@"/license/Name", null).InnerText = Name;
          doc.ChildNodes[0].SelectSingleNode(@"/license/Date", null).InnerText = StartDate.ToShortDateString();
          doc.ChildNodes[0].SelectSingleNode(@"/license/UpdateTo", null).InnerText = UpdateTo.ToShortDateString();

          MD5 md5 = new MD5CryptoServiceProvider();
          byte[] data = System.Text.Encoding.UTF8.GetBytes(Name + StartDate.ToShortDateString() + UpdateTo.ToShortDateString() + "SomePasswordKey");
          byte[] hash = md5.ComputeHash(data);
          doc.ChildNodes[0].SelectSingleNode(@"/license/Signature", null).InnerText = Convert.ToBase64String(hash);
          doc.Save(System.IO.Path.Combine(Path, "license.xml"));
        }
      }

    * This source code was highlighted with Source Code Highlighter.


    At the output, we get something like this license.xml file

     Автор
     15.06.2009
     15.12.2009
     w673nrcuvxjnn7R4heEnvw==


    * This source code was highlighted with Source Code Highlighter.


    Next, in the protected application, we need to pass a test, this is done by calling the Verify method each time the application starts:
    public class LicenseVerify
      {
        public LicenseVerify() { }
        public string Name { get; private set; }
        public DateTime StartDate {get; private set;}
        public DateTime UpdateTo {get; private set;}

        public void Verify()
        {
          string File = "license.xml";
          if (!System.IO.File.Exists(File))
          {
            throw new ApplicationException ("Ваша копия программы не лицензирована! Не найден файл лицензии License.xml.\n Обратитесь к автору.");
          }
          
            XmlDocument doc = new XmlDocument();
            doc.Load(File);
            string sig1;
            string Signature;
            try
            {
              string Name = doc.ChildNodes[0].SelectSingleNode(@"/license/Name", null).InnerText;
              string StartDate = doc.ChildNodes[0].SelectSingleNode(@"/license/Date", null).InnerText;
              string UpdateTo = doc.ChildNodes[0].SelectSingleNode(@"/license/UpdateTo", null).InnerText;
              Signature = doc.ChildNodes[0].SelectSingleNode(@"/license/Signature", null).InnerText;
              MD5 md5 = new MD5CryptoServiceProvider();
              byte[] data = System.Text.Encoding.UTF8.GetBytes(Name + StartDate + UpdateTo + "SomePasswordKey");
              byte[] hash = md5.ComputeHash(data);
              sig1 = Convert.ToBase64String(hash);
              this.Name = Name;
              this.StartDate = Convert.ToDateTime(StartDate);
              this.UpdateTo = Convert.ToDateTime(UpdateTo);
            }
            catch (Exception)
            {
              
              throw new ApplicationException("Ваша копия программы не лицензирована!\nОшибка чтения файла лицензии!\nОбратитесь к автору.");
            }

            if (sig1 != Signature)
            {
              throw new ApplicationException("Ваша копия программы не лицензирована!\nОшибка чтения файла лицензии!\nОбратитесь к автору.");

            }
            if (DateTime.Now < this.StartDate)
            {
              throw new ApplicationException(string.Format( "Ваша копия программы не лицензирована!\nСрок действия лицензии еще не начался! Начало {0}\nОбратитесь к автору.",StartDate.ToShortDateString()));

            }
            
            if (App.Created > this.UpdateTo)
            {
              throw new ApplicationException(string.Format("Ваша копия программы не лицензирована!\nВы не имеет право использовать это обновление.\nВы могли получать обновления до {0}\nОбратитесь к автору.", UpdateTo.ToShortDateString()));

            }
        }
      }

    * This source code was highlighted with Source Code Highlighter.


    The negative thing is that having solved SomePasswordKey, having received the code by disassembling, the attacker can create his own license file.
    A positive point may be the ease of implementation, when crypto protection does not come first.

    ToDo List:
    • Add the ability to create temporary evaluation versions of the program
    • Add the ability to bind a license to a specific computer
    • It is possible to create a web service where requests to create license keys and automatically receive ready-made keys will be sent, or the basis for refusal

    Also popular now: