php - Check if a generated license is valid -
i have php script generates strings used license keys:
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++; }
after running script once, got these:
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
what trying change have function check if key has been generated using script. currently, thinking setting $key
md5 of 1 specific string (for example, test
) but, of course, returns strings same.
can help?
note:
this solution on assumption want licence key in fixed format
(see below) , still self authenticated
format : xxxxx-xxxxx-xxxxx-xxxxx-xxxx
if not case refer @ircmaxell
better solution
introduction
self authenticated serial tricky solution because:
- limited size of serial
- it need authenticate self without database or storage
- if private key leaked .. can reversed
example
$option = new checkprofile(); $option->name = "my application"; // application name $option->version = 0.9; // application version $option->username = "benedict lewis"; // can limit key per user $option->uniqid = null; // add if $checksum = new checksum($option); $key = $checksum->generate(); var_dump($key, $checksum->check($key));
output
string '40b93-c7fd6-ab5e6-364e2-3b96f' (length=29) boolean true
please note modification in options change key , make invalid;
checking collision
i ran simple test
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]) , $collision ++; $checksum->check($key) or $error ++; $cache[$key] = true; } printf("fond %d collision , %d errors in 100000 entries", $collision, $error);
output
fond 0 collision , 0 errors in 100000 entries
better security
by default script uses sha1
php
has lot of better hash functions
can following code
print_r(hash_algos());
example
$checksum = new checksum($option, null, "sha512");
class used
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 options $this->profile->keys = $keys; // serialise convert 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) $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); // important return $key === $this->generate($keys); } }