9

ライセンス キーとして使用されるいくつかの文字列を生成する PHP スクリプトがあります。

function KeyGen(){
     $key = md5(microtime());
     $new_key = '';
     for($i=1; $i <= 25; $i ++ ){
               $new_key .= $key[$i];
               if ( $i%5==0 && $i != 25) $new_key.='-';
     }
  return strtoupper($new_key);
  }
$x = 0;
while($x <= 10) {
  echo KeyGen();
  echo "<br />";
$x++; 
}

スクリプトを 1 回実行した後、次のようになりました。

8B041-EC7D2-0B9E3-09846-E8C71
C8D82-514B9-068BC-8BF80-05061
A18A3-E05E5-7DED7-D09ED-298C4
FB1EC-C9844-B9B20-ADE2F-0858F
E9AED-945C8-4BAAA-6938D-713ED
4D284-C5A3B-734DF-09BD6-6A34C
EF534-3BAE4-860B5-D3260-1CEF8
D84DB-B8C72-5BDEE-1B4FE-24E90
93AF2-80813-CD66E-E7A5E-BF0AE
C3397-93AA3-6239C-28D9F-7A582
D83B8-697C6-58CD1-56F1F-58180

私が今やろうとしているのは、スクリプトを使用してキーが生成されたかどうかを確認する別の関数があるように変更することです。現在、私が考えているのは、$keyを 1 つの特定の文字列 (たとえば、test) の MD5 に設定することですが、もちろん、すべての文字列が同じように返されます。

誰でも助けることができますか?

4

5 に答える 5

14

ノート:

fixed formatこの解決策は、ライセンス キーを常に(以下を参照)保持しておきたいという前提に基づいています。self authenticated

  FORMAT : XXXXX-XXXXX-XXXXX-XXXXX-XXXX

そうでない場合は@ircmaxell、より良い解決策を参照してください

序章

自己認証シリアルは、次の理由からトリッキーなソリューションです。

  • シリアルの限定サイズ
  • データベースやストレージなしで自己認証する必要があります
  • 秘密鍵が漏洩した場合..簡単に元に戻すことができます

$option = new CheckProfile();
$option->name = "My Application"; // Application Name
$option->version = 0.9; // Application Version
$option->username = "Benedict Lewis"; // you can limit the key to per user
$option->uniqid = null; // add if any


$checksum = new Checksum($option);
$key = $checksum->generate();
var_dump($key, $checksum->check($key));

出力

string '40B93-C7FD6-AB5E6-364E2-3B96F' (length=29)
boolean true

オプションを変更すると、キーが変更されて無効になることに注意してください。

衝突のチェック

この簡単なテストを実行しました

set_time_limit(0);

$checksum = new Checksum($option);
$cache = array();
$collision = $error = 0;
for($i = 0; $i < 100000; $i ++) {
    $key = $checksum->generate();
    isset($cache[$key]) and $collision ++;
    $checksum->check($key) or $error ++;
    $cache[$key] = true;
}

printf("Fond %d collision , %d Errors  in 100000 entries", $collision, $error);

出力

  Fond 0 collision , 0 Errors in 100000 entries 

セキュリティの向上

デフォルトでは、スクリプトは使用しますsha1が、次のコードでPHPそれhash functionsを得ることができます。

print_r(hash_algos());

$checksum = new Checksum($option, null, "sha512");

使用クラス

class Checksum {
    // Used used binaray in Hex format
    private $privateKey = "ec340029d65c7125783d8a8b27b77c8a0fcdc6ff23cf04b576063fd9d1273257"; // default
    private $keySize = 32;
    private $profile;
    private $hash = "sha1";

    function __construct($option, $key = null, $hash = "sha1") {
        $this->profile = $option;
        $this->hash = $hash;

        // Use Default Binary Key or generate yours
        $this->privateKey = ($key === null) ? pack('H*', $this->privateKey) : $key;
        $this->keySize = strlen($this->privateKey);
    }

    private function randString($length) {
        $r = 0;
        switch (true) {
            case function_exists("openssl_random_pseudo_bytes") :
                $r = bin2hex(openssl_random_pseudo_bytes($length));
                break;
            case function_exists("mcrypt_create_ivc") :
            default :
                $r = bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM));
                break;
        }
        return strtoupper(substr($r, 0, $length));
    }

    public function generate($keys = false) {
        // 10 ramdom char
        $keys = $keys ?  : $this->randString(10);
        $keys = strrev($keys); // reverse string

        // Add keys to options
        $this->profile->keys = $keys;

        // Serialise to convert to string
        $data = json_encode($this->profile);

        // Simple Random Chr authentication
        $hash = hash_hmac($this->hash, $data, $this->privateKey);
        $hash = str_split($hash);

        $step = floor(count($hash) / 15);
        $i = 0;

        $key = array();
        foreach ( array_chunk(str_split($keys), 2) as $v ) {
            $i = $step + $i;
            $key[] = sprintf("%s%s%s%s%s", $hash[$i ++], $v[1], $hash[$i ++], $v[0], $hash[$i ++]);
            $i ++; // increment position
        }
        return strtoupper(implode("-", $key));
    }

    public function check($key) {
        $key = trim($key);
        if (strlen($key) != 29) {
            return false;
        }
        // Exatact ramdom keys
        $keys = implode(array_map(function ($v) {
            return $v[3] . $v[1];
        }, array_map("str_split", explode("-", $key))));

        $keys = strrev($keys); // very important
        return $key === $this->generate($keys);
    }
}
于 2013-04-25T13:04:05.300 に答える
-2

このアルゴリズムで重複したキーを取得することは不可能ではないことに注意してください。可能性は低いですが、宝くじに当選することもあります。キーがすでに存在するかどうかを確認するには、キーをデータベースまたはファイルに保存する必要があります。

于 2013-04-25T12:58:18.100 に答える