# Формат серийного номера

### Структура серийного номера

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

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

### Формат блоков

ID | Название | Размер (байт) | Описание | Пример
--- | --- | --- | --- | ---
0x01 | Версия | 1 | Блок содержит версию серийного номера размером в 1 байт. Версия должна быть равна 1. | 01 01
0x02 | Имя пользователя | 1 + N | Блок содержит имя пользователя в кодировке UTF-8. Перед именем пользователя располагается 1 байт длины имени. Таким образом, длина имени пользователя не может превышать 255 байт. Завершающий 0 не требуется. | 02 04 4A 5F 48 4E
0x03 | E-Mail | 1 + N | Блок содержит e-mail пользователя в кодировке UTF-8. Перед e-mail'ом располагается 1 байт длины. Таким образом, длина e-mail не может превышать 255 байт. Завершающий 0 не требуется. | 03 07 61 40 62 2E 63 6F 6D
0x04 | Идентификатор оборудования | 1 + N | Блок содержит идентификатор оборудования, возвращенный функцией VMProtectGetCurrentHWID(). Функция возвращает строку в кодировке base-64, в серийный номер помещается раскодированный вариант строки. Длина блока данных должна быть кратна 4. Перед блоком данных располагается байт длины. Максимальная длина блока - 32 байта. | 04 08 E1 E2 E3 E4 A1 A2 A3 A4
0x05 | Дата окончания лицензии | 4 | Блок содержит дату окончания действия серийного номера. Формат хранения даты описан ниже. | 05 01 0A 07 DA
0x06 | Максимальное время работы | 1 | Блок содержит 1 байт с временем работы программы в минутах. Максимальное время работы, таким образом, может составлять 255 минут. | 06 05
0x07 | Код продукта | 8 | Блок содержит код продукта - 8 байт, которые создаются VMProtect и выгружаются при экспорте параметров продукта. Выгружаются они в кодировке base-64, перед помещением в серийный номер строку необходимо преобразовать в массив байт. Размер массива должен быть строго равен 8 байтам. Этот блок является обязательным, без него защищенная программа будет работать некорректно! | 07 01 02 03 04 05 06 07 08
0x08 | Данные пользователя | 1 + N | Блок содержит до 255 байт пользовательских данных. Система лицензирования не анализирует эти данные и возвращает их при вызове функции VMProtectGetSerialNumberData(). Перед блоком данных располагается байт, содержащий размер пользовательских данных. | 08 05 01 02 03 04 05
0x09 | Максимальная дата сборки | 4 | Блок содержит максимальную дату сборки приложения, с которым будет работать этот серийный номер. Формат хранения даты описан ниже. | 09 01 0A 07 DA
0xFF | Контрольная сумма | 4 | Блок содержит контрольную сумму серийного номера. Блок располагается последним и контрольная сумма считается для всех блоков, идущих перед этим. Подробнее о расчете контрольной суммы написано ниже. | FF 01 02 03 04

### Формат хранения даты

Даты в серийном номере хранятся в виде двойного слова - 0xYYYYMMDD. Старшее слово содержит год, а младшее - день и месяц. Байты расположены в порядке Little Endian - от младшего к старшему. В случае, если имеется указатель на первый байт записи, то дата может быть считана и записана следующим кодом:

    byte *pDate = 0xNNNNNN; // адрес даты
    *(DWORD *)pDate = (2010 << 16) | (10 << 8) | 1; // October 1, 2010
    DWORD dwExp = *(DWORD *)pDate;

### Подсчет контрольной суммы

Контрольная сумма серийного номера вычисляется при помощи алгоритма хеширования SHA-1. Результатом работы алгоритма являются пять 32-битных слов. Первое слово используется в качестве контрольной суммы серийного номера. Обратите внимание: слово записывается в формате Little Endian (от младшего байта к старшему). В строковом представлении хеша SHA-1 используется формат Big Endian - числа записываются от старшего байта к младшему, поэтому если SHA-1 генерируется функцией, которая возвращает строку (как в PHP), то первые четыре байта хеша необходимо предварительно развернуть.

### Дополнительная информация

Блоки с номерами, отличными от описанных выше, игнорируются системой лицензирования. Возможно появление новых блоков в будущих версиях. Не рекомендуется создавать свои блоки, используя свободные идентификаторы! Во-первых, это может привести к неработоспособности ключа с новыми версиями системы лицензирования. А во-вторых, защищаемая программа все равно не сможет прочитать значения этих блоков. Для хранения какой-либо информации в ключе нужно использовать поле User Data, которое предназначено именно для этого.

Серийный номер не содержит "соли" (SALT) - случайной информации, предназначенной для того, чтобы ключи для одних и тех же данных получались разными. Эта задача возлагается на алгоритм шифрования. Если необходимы отличия на уровне серийных номеров, скажем для серии ключей, проданных в организацию, можно записать номер ключа строкой в поле имени пользователя (ООО "Компания", ключ 1 из 10) или занести эту информацию в поле User Data в любом удобном для разработчика формате.

© 2006-2015 Copyright VMProtect Software