Внедрение серийных номеров программного обеспечения - PullRequest
4 голосов
/ 06 апреля 2011

Допустим, я написал программу и хочу распространить ее среди людей. Я хочу иметь возможность запросить серийный номер у пользователя во время установки, который подтвердит наличие у него лицензионной копии программного обеспечения. Кроме того, я хочу, чтобы серийный номер сохранял информацию о том, к какому выпуску программного обеспечения они имеют доступ и когда истекает срок действия лицензии.

Для этого есть как минимум два концептуальных способа:

  1. Создайте сериал на сервере, где пользователь покупает программное обеспечение, и отправьте его по электронной почте. Программное обеспечение подключается к серверу во время установки и активирует продукт. Сервер возвращает лицензионные привилегии и срок действия. Сериал не имеет определенного формата / математических правил, он просто проверяется по базе данных на сервере.

  2. Создайте серийный номер для клиента и отправьте его по электронной почте. Сериал имеет некоторые специальные математические свойства, которые позволяют программе проверять, действительна ли она, какой лицензии она соответствует и когда она истекает.

Меня больше всего интересует 2-й метод. Какие методы используются при кодировании этой информации в серийный номер? Если бы вы могли дать краткий обзор, это было бы здорово. В противном случае, можете ли вы порекомендовать хорошие книги или сайты, которые обсуждают это?

Мне кажется странным, что за все годы, которые я занимался кодированием, я никогда не видел ни реализации, ни описания этих методов.

Ответы [ 2 ]

3 голосов
/ 29 апреля 2011

То, о чем вы думаете, - это создание собственного модуля лицензирования.Ничего плохого в этом нет, и если вы свернете свой собственный, это будет бесплатно (только ваше время, чтобы кодировать и отлаживать его).Однако взломать его будет чрезвычайно просто, поэтому, если вы делаете это, чтобы получить какое-то соответствие лицензии (например, защиту от копирования), я бы не стал беспокоиться.

Собираетесь ли вы каким-то образом привязать его к физической машине?Одним из способов является получение серийного номера ЦП, серийного номера HD, MAC-адреса и т. Д. Или некоторой комбинации вышеперечисленного, хэширование их и использование хеш-кода для проверки при запуске, чтобы убедиться, что лицензия действительна.Конечно, если пользователь что-то изменит, проверка не удастся, и он может быть раздражен тем, что его программное обеспечение больше не будет работать, даже если у него есть действующая лицензия.

Если вы делаете это для защиты от нелегального копирования или использования, предложенную вами схему обычно довольно просто взломать - взломщик ищет, где вы проверяете правильную лицензию, и просто исправляет ассемблер.код для разветвления или всегда возвращать положительный результат.Если ваше приложение .NET, они могут просто вернуться к исходному коду и удалить часть проверки лицензии.

Отказ от ответственности: я работаю в компании по управлению лицензиями / инструментами защиты от копирования ([Wibu-Systems]) 1 , и это все, что мы делаем, поэтому мы знаем, как легко победить большинствосистемы.

Я бы порекомендовал один из трех способов:

  1. Оставьте ваше приложение незащищенным и надеюсь, что соотношение продаж и пиратских копий будет разумным.
  2. Сверните простую систему, нопризнайте, что если у программного обеспечения есть ценность, кто-то взломает это быстро и легко.Будьте готовы к некоторому сложному кодированию и обслуживанию, чтобы сделать это даже наполовину прилично.
  3. Купите систему защиты коммерческого качества, такую ​​как CodeMeter , HASP или KeyLok.Некоторые из них лучше, чем другие (мы считаем, что у нас это лучше всего), но ни один не является бесплатным.
1 голос
/ 18 апреля 2011

Хорошо, так две недели без ответа.Я собираюсь ответить очень простым методом, который я придумал для генерации относительно безопасных и хорошо масштабируемых серийных номеров с использованием элементарных методов.

Как математик, я вполне уверен, что есть некоторыепродвинутые методы для хранения всех видов информации в серийном номере - но я в основном заинтересован в быстрых и грязных действиях.

Вот наивный, нематематический метод грубой силы, который нужно рассмотреть:

Создайте массив byte[], содержащий символы, которые вы хотите использовать.Вы можете использовать только гекс, но нет причин ограничивать себя.Почему бы не использовать весь буквенно-цифровой диапазон минус «0» / «O» и «1» / «I» (по понятным причинам).

Затем напишите функцию следующим образом (например, C #):

byte[] genRandomSerial(int length, byte[] characters, Random r)
{
  var sn = new byte[length];

  for (int i = 0; i < length; i++)
    sn[i] = characters[r.Next(0, characters.Length)];

  return sn;
}

Это даст вам случайный серийный номер, который, как мы не знаем, действителен или нет.

Далее:

int sum(byte[] sn, MD5 md5)
{
  val = 0;

  foreach (byte b in md5.ComputeHash(sn))
    val += (int)b;

  return val;
}

а затем

bool validate(byte[] sn, uint radix, uint expected, MD5 md5)
{
  return (sum(sn, md5) % radix == expected);
}

Теперь у нас есть способ суммирования 16-байтового вывода хеш-функции MD5 и оценки, равна ли сумма по модулю n некоторым x .

Теперь определитесь, сколько серийных номеров вы хотите существовать.Чем больше существует серийных номеров, тем легче кому-то случайно угадать правильную комбинацию.

Разделите ваш случайный серийный номер на блоки.Скажем, 5 блоков из 4, что дает 20 символов в форме: ABCD-EFGH-IJKL-MNOP-QRST

Создайте 5 массивов из вашего серийного номера:

{A, B, C, D}, {E, F, G, H}, {I, J, K, L}, {M, N, O, P} и {Q, R, S, T}.

проверьте, чтобы убедиться, что ваши 5 массивов проверяются следующим образом:

if (validate(block1, radix, expected, md5))
  // This block is valid.

Если вы установите основание на 2, то вероятность того, что блок будет действительным, равна 1/2.Если вы установите основание на 10, то есть вероятность 1/10, что блок будет действительным.Если у вас есть 5 блоков, и вы устанавливаете радиусы каждый на 10, то вероятность того, что весь серийный номер будет действительным, составляет 0,1 ^ 5 = 0,00001.(Другими словами, 1 из каждых 100000 случайных серий будет действительным. Это означает, что если вы используете полный буквенно-цифровой диапазон минус «0» / «O», «1» / «I», то у вас есть (8 + 24) ^ n * 0.00001 = ~ 1.2 * 10 ^ 19 действительных ключей для серийной длины 20. Это много - но помните, что вы все равно не найдете их все. Чем выше ваш радиус, тем выше безопасностьпоследовательный будет, но чем дольше будет генерироваться).

Обратите внимание, 'ожидаемое' должно быть где-то между 0 и radix-1 .

Так что теперь мыУ нас есть способ проверки правильности определенного серийного номера, но как мы можем сохранить тип этого серийного номера?На самом деле, у нас уже есть способ сделать это.Взяв весь случайный (но проверенный) серийный 'sn':

int licenseType = sum(sn, md5) % 4; // Where 4 is the number of licenses you want to have

if (licenseType == 0)
{
  // Evaluation
}
else if (licenseType == 1)
{
  // Standard
}
else if (licenseType == 2)
{
  // Full
}
else // licenseType == 3
{
  // Unrestricted
}

Количество лицензий каждого типа будет постепенно выравниваться по мере того, как вы генерируете все больше и больше ключей.

Если вы хотитеДля хранения дополнительной информации в ключе, например даты истечения срока действия, вы можете использовать аналогичные методы.Вы можете, например, взять сумму нечетных символов по модулю 12, чтобы получить истекающий месяц, и по модулю 31 сумму четных символов, чтобы дать истекающий день.

Чем больше этих ограничений и-для подразделения вы применяете, тем больше времени потребуется для создания каждого типа ключа.

...