SecretKey: $secretkey
"; $key = base32static::decode($secretkey); print "Key(base 32 decode): $key
"; $unixtimestamp = time() / 30; print "UnixTimeStamp (time()/30): $unixtimestamp
"; for ($i = - ($rangein30s); $i <= $rangein30s; $i++) { $checktime = (int)($unixtimestamp + $i); print "Calculating oath_hotp from (int)(unixtimestamp +- 30sec offset): $checktime basing on secret key
"; $thiskey = self::oath_hotp($key, $checktime, true); print "======================================================
"; print "CheckTime: $checktime oath_hotp:" . $thiskey . "
"; $result = $result . " # " . self::oath_truncate($thiskey, 6, true); } return $result; } // public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) // { // $url = "http://chart.apis.google.com/chart"; // $url = $url . "?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/"; // $url = $url . $username . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer); // return $url; // } public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) { $url = "https://api.qrserver.com/v1/create-qr-code/"; $url = $url . "?size=100x100&data=otpauth://totp/"; $url = $url . $username . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer); return $url; } public static function generateRandomClue($length = 32) { $b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM"; $s = ""; for ($i = 0; $i < $length; $i++) $s .= $b32[rand(0, 31)]; return $s; } private static function hotp_tobytestream($key) { $result = ""; $last = strlen($key); for ($i = 0; $i < $last; $i = $i + 2) { $x = $key[$i] . $key[$i + 1]; $x = strtoupper($x); $x = hexdec($x); $result = $result . chr($x); } return $result; } private static function oath_hotp($key, $counter, $debug = false) { $result = ""; $orgcounter = $counter; $cur_counter = array(0, 0, 0, 0, 0, 0, 0, 0); if ($debug) { print "Packing counter $counter (" . dechex($counter) . ")into binary string - pay attention to hex representation of key and binary representation
"; } for ($i = 7; $i >= 0; $i--) { // C for unsigned char, * for repeating to the end of the input data $cur_counter[$i] = pack('C*', $counter); if ($debug) { print $cur_counter[$i] . "(" . dechex(ord($cur_counter[$i])) . ")" . " from $counter
"; } $counter = $counter >> 8; } if ($debug) { foreach ($cur_counter as $char) { print ord($char) . " "; } print "
"; } $binary = implode($cur_counter); // Pad to 8 characters str_pad($binary, 8, chr(0), STR_PAD_LEFT); if ($debug) { print "Prior to HMAC calculation pad with zero on the left until 8 characters.
"; print "Calculate sha1 HMAC(Hash-based Message Authentication Code http://en.wikipedia.org/wiki/HMAC).
"; print "hash_hmac ('sha1', $binary, $key)
"; } $result = hash_hmac('sha1', $binary, $key); if ($debug) { print "Result: $result
"; } return $result; } private static function oath_truncate($hash, $length = 6, $debug = false) { $result = ""; // Convert to dec if ($debug) { print "converting hex hash into characters
"; } $hashcharacters = str_split($hash, 2); if ($debug) { print_r($hashcharacters); print "
and convert to decimals:
"; } for ($j = 0; $j < count($hashcharacters); $j++) { $hmac_result[] = hexdec($hashcharacters[$j]); } if ($debug) { print_r($hmac_result); } // http://php.net/manual/ru/function.hash-hmac.php // adopted from brent at thebrent dot net 21-May-2009 08:17 comment $offset = $hmac_result[19] & 0xf; if ($debug) { print "Calculating offset as 19th element of hmac:" . $hmac_result[19] . "
"; print "offset:" . $offset; } $result = ( (($hmac_result[$offset + 0] & 0x7f) << 24) | (($hmac_result[$offset + 1] & 0xff) << 16) | (($hmac_result[$offset + 2] & 0xff) << 8) | ($hmac_result[$offset + 3] & 0xff) ) % pow(10, $length); return $result; } }