Pull to refresh

Простой способ добавить поддержку файлов лицензий в Ваше приложение .Net

Reading time6 min
Views17K
Некоторое время назад приятель попросил автоматизировать часть рутинной работы его бизнеса. На тот момент я предвкушал наступление грядущего сокращения и с удовольствием согласился.
Разработка заняла три полных цикла и сейчас подходит к концу четвертый завершающий цикл работы над программой и у меня возникла идея двинуть свой продукт дальше в массы. Сказано сделано, началась работа по составлению договоров, изменению дизайна, отбутфорсингу и других прочих лабудей и возник интереснейший вопрос — а как защитить программу от не лицензионного использования и не дать возможности просто ее копировать?

Порыскав по интернету, точнее по порталу CodeProject, нашел несколько реализаций с применением файлов лицензий.
В теории задача решается просто:
  1. Создадим файл xml с нужным нам содержанием
  2. Подписываем файл с помощью класса SignedXml
  3. В приложении проверяем подпись. Если проверка удалась — смотрим содержание файла, если нет — сразу выпадаем с ошибкой

На практике объект SignedXml требует экземпляр AssimetricAlgorithm шифрования. В найденныx примерах использовалось несимметричное шифрование любым установленным на компьютере сертификатом и последующей расшифровкой экспортированным открытым ключом. С учетом того, что я через некоторое время собираюсь переустанавливать систему нужно было заморочиться на экспорте сертификата, да и не вариант что он вообще может потом встать обратно, и еще очень длинный код реализации.
Я задумался, ведь может быть способ проще. И нашел.
Вся работа Подписчика заключается в добавлении к xml некой строки, которая должна быть проверена. Так почему бы мне не записать туда свою строку сформированную по определенному алгоритму. Мой способ использует метод симметричного шифрования, так сказать.
Мне нужно было проверить наступил ли срок лицензии, до какого числа возможно получение обновлений и кому собственно принадлежит эта лицензия.
Я создал два класса: один для создания файла лицензии, другой для его проверки.
Метод очень прост. Берем входные параметры для создания лицензии, записываем все в xml. Затем конкатируем эти самые параметры, добавляем к ним некую константу, получаем хэш, который и будет нашей подписью и дописываем его в конец xml в соответствующий раздел.

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

      XmlDocument doc = new XmlDocument();
      doc.LoadXml(@"<license>
            <Name></Name>
            <Date></Date>
            <UpdateTo></UpdateTo>
            <Signature></Signature>
            </license>"
);
      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.


На выходе получаем примерно такой вот файл license.xml
<license>
 <Name>Автор</Name>
 <Date>15.06.2009</Date>
 <UpdateTo>15.12.2009</UpdateTo>
 <Signature>w673nrcuvxjnn7R4heEnvw==</Signature>
</license>


* This source code was highlighted with Source Code Highlighter.


Далее в защищаемом приложении нам нужно пройти проверку, делается это путем вызова метода Verify при каждом запуске приложения:
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.


Отрицательным может быть то, что разгадав SomePasswordKey, получив дизасемлированием код, злоумышленник может создать свой файл лицензии.
Положительным моментом может служить простота реализации, когда криптозащита не стоит на первом месте.

ToDo List:
  • Добавить возможность создания временных ознакомительных версий программы
  • Добавить возможность привязки лицензии к определенному компьютеру
  • Возможно создать веб сервис, куда будут отравляться запросы на создание лицензионных ключей и автоматическое получение готовых ключей или основание в отказе
Tags:
Hubs:
Total votes 24: ↑18 and ↓6+12
Comments16

Articles