在序列号中嵌入数据

Embedding data in a serial number

我正在考虑实施概述的 PVKS here。我让它按照文章中的方式工作(但在 PHP 中),但是我有一个额外的要求,我想弄清楚如何满足。我试图弄清楚如何将日期和 3 位数字嵌入到生成的代码中。我什至不确定从哪里开始,所以老实说我什么都没试过。不幸的是,它们的组合不会是唯一的,所以我无法将它们散列为种子值。据我所知,我也不能让它们成为 getKeyByte 函数的一部分,因为该函数的输入应该只是种子和一些参数,其中这些参数定义有效密钥的算法。它们在生成器和验证器之间必须相同,因此它们必须是静态的。这种任务有公认的做法吗?

设法自己解决了这个问题。我意识到我试图找到一种可以将值编码为密钥字节的方法,这让事情变得过于复杂。这样做的方法(嗯,我这样做的方法)只是在密钥字节之后和校验和之前添加额外的字节。它们不需要像其他密钥字节那样进行验证,但会影响校验和。

以下是我的 class 中与生成和验证密钥相关的部分,其中包含我需要添加的新部分。

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!
}