Хорошо, так две недели без ответа.Я собираюсь ответить очень простым методом, который я придумал для генерации относительно безопасных и хорошо масштабируемых серийных номеров с использованием элементарных методов.
Как математик, я вполне уверен, что есть некоторыепродвинутые методы для хранения всех видов информации в серийном номере - но я в основном заинтересован в быстрых и грязных действиях.
Вот наивный, нематематический метод грубой силы, который нужно рассмотреть:
Создайте массив 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 сумму четных символов, чтобы дать истекающий день.
Чем больше этих ограничений и-для подразделения вы применяете, тем больше времени потребуется для создания каждого типа ключа.