Я смотрю на реализацию PVKS, как изложено Вот. У меня это работает, как представлено в статье (но в PHP), однако у меня есть дополнительное требование, которое я пытаюсь выяснить, как выполнить. Я пытаюсь выяснить, как я должен вставить дату и трехзначное число в сгенерированный код. Я даже не уверен, с чего начать, поэтому, честно говоря, ничего не пробовал. К сожалению, они не будут уникальными в комбинации, поэтому я не могу хэшировать их для начального значения. Насколько я могу судить, они не могут быть частью функции getKeyByte, поскольку входные данные для этой функции должны быть только начальным числом и некоторыми аргументами, где эти аргументы определяют алгоритм для действительного ключа. Они должны быть одинаковыми между генератором и валидатором, поэтому они должны быть статичными. Есть ли принятая практика для такого рода задач?
Удалось выяснить это сам. Я понял, что слишком усложнил ситуацию, пытаясь найти способ, которым я мог бы закодировать значение в ключевой байт. Способ сделать это (ну, как я это сделал) — просто добавить дополнительные байты после ключевых байтов и до контрольной суммы. Их не нужно проверять, как и другие ключевые байты, но они влияют на контрольную сумму.
Ниже часть моего класса, связанная с генерацией и проверкой ключей, с новыми разделами, которые мне нужно было добавить.
static public function generateKey($extraKeyArgs = array(), $encodedData = array())
{
$args = self::instanceKeyArgs($extraKeyArgs);
$keyBytes = array();
$seed = self::getSeed();
$hexSeed = self::intToHex($seed,self::$seedWidth);
$key = $hexSeed;
$numKeys = count($args);
for ($i=0; $i < $numKeys; $i++) {
list($a, $b, $c) = $args[$i];
$keyBytes[$i] = self::getKeyByte($seed, $a, $b, $c, self::$keyWidthBytes);
$key .= self::intToHex($keyBytes[$i],self::$keyWidthHex);
}
// Section added to handle encoded data
foreach ($encodedData as $data) {
// Make $data an integer value, one byte wide.
$data = (((int) $data) & 255);
$keyBytes[] = $data;
$numKeys++;
$key .= self::intToHex($data,self::$keyWidthHex);
}
// End Section
$checksum = self::getChecksum($key);
$key = $hexSeed . self::$seperator;
for ($i=0; $i < $numKeys; $i++) {
$key .= self::intToHex($keyBytes[$i],self::$keyWidthHex);
if ($i & 1) {
$key .= self::$seperator;
}
}
if (substr($key, -1) !== self::$seperator) {
$key .= self::$seperator;
}
$key .= $checksum;
return $key;
}
static public function checkKey($key, $extraKeyArgs = array(), &$data = array())
{
$args = self::instanceKeyArgs($extraKeyArgs);
$numKeys = count($args);
if (!self::checkKeyChecksum($key)) {
return false; // Failed checksum! Maybe a mistype or optical reader error?
}
$key = self::normalizeKey($key);
// TODO - we would check against a blacklist here if we wanted to implement that.
$seed = hexdec(substr($key,0,self::$seedWidth));
if (!is_int($seed) || $seed < 1) {
return false; // Failed to get seed. Are you sure this key came from here?
}
$key = substr($key, self::$seedWidth, (strlen($key) - (self::$seedWidth + self::$checksumWidth)));
for ($i=0; $i < $numKeys; $i++) {
$keyByte = substr($key, 0, self::$keyWidthHex);
$key = substr($key, self::$keyWidthHex);
list($a, $b, $c) = $args[$i];
if ($keyByte !== self::intToHex(self::getKeyByte($seed, $a, $b, $c, self::$keyWidthBytes),2)) {
return false; // Key byte failed check. Possible forgery attempt?
}
}
// This line added to handle encoded data
$data = array_map('hexdec', str_split($key, self::$keyWidthHex));
return true; // Valid Key, Yay!
}
Других решений пока нет …