diff --git a/OTP-Detect.php b/OTP-Detect.php new file mode 100644 index 0000000..b87f409 --- /dev/null +++ b/OTP-Detect.php @@ -0,0 +1,282 @@ +. + * + * PHP Google two-factor authentication module. + * + * See http://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/ + * for more details + * + * @author Phil + **/ + +class Google2FA { + + const keyRegeneration = 30; // Interval between key regeneration + const otpLength = 6; // Length of the Token generated + + private static $lut = array( // Lookup needed for Base32 encoding + "A" => 0, "B" => 1, + "C" => 2, "D" => 3, + "E" => 4, "F" => 5, + "G" => 6, "H" => 7, + "I" => 8, "J" => 9, + "K" => 10, "L" => 11, + "M" => 12, "N" => 13, + "O" => 14, "P" => 15, + "Q" => 16, "R" => 17, + "S" => 18, "T" => 19, + "U" => 20, "V" => 21, + "W" => 22, "X" => 23, + "Y" => 24, "Z" => 25, + "2" => 26, "3" => 27, + "4" => 28, "5" => 29, + "6" => 30, "7" => 31 + ); + + /** + * Generates a 16 digit secret key in base32 format + * @return string + **/ + public static function generate_secret_key($length = 16) { + $b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM"; + $s = ""; + + for ($i = 0; $i < $length; $i++) + $s .= $b32[rand(0,31)]; + + return $s; + } + + /** + * Returns the current Unix Timestamp devided by the keyRegeneration + * period. + * @return integer + **/ + public static function get_timestamp() { + return floor(microtime(true)/self::keyRegeneration); + } + + /** + * Decodes a base32 string into a binary string. + **/ + public static function base32_decode($b32) { + + $b32 = strtoupper($b32); + + if (!preg_match('/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match)) + throw new Exception('Invalid characters in the base32 string.'); + + $l = strlen($b32); + $n = 0; + $j = 0; + $binary = ""; + + for ($i = 0; $i < $l; $i++) { + + $n = $n << 5; // Move buffer left by 5 to make room + $n = $n + self::$lut[$b32[$i]]; // Add value into buffer + $j = $j + 5; // Keep track of number of bits in buffer + + if ($j >= 8) { + $j = $j - 8; + $binary .= chr(($n & (0xFF << $j)) >> $j); + } + } + + return $binary; + } + + /** + * Takes the secret key and the timestamp and returns the one time + * password. + * + * @param binary $key - Secret key in binary form. + * @param integer $counter - Timestamp as returned by get_timestamp. + * @return string + **/ + public static function oath_hotp($key, $counter) + { + if (strlen($key) < 8) + throw new Exception('Secret key is too short. Must be at least 16 base 32 characters'); + + $bin_counter = pack('N*', 0) . pack('N*', $counter); // Counter must be 64-bit int + $hash = hash_hmac ('sha1', $bin_counter, $key, true); + + return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT); + } + + /** + * Verifys a user inputted key against the current timestamp. Checks $window + * keys either side of the timestamp. + * + * @param string $b32seed + * @param string $key - User specified key + * @param integer $window + * @param boolean $useTimeStamp + * @return boolean + **/ + public static function verify_key($b32seed, $key, $window = 4, $useTimeStamp = true) { + + $timeStamp = self::get_timestamp(); + + if ($useTimeStamp !== true) $timeStamp = (int)$useTimeStamp; + + $binarySeed = self::base32_decode($b32seed); + + for ($ts = $timeStamp - $window; $ts <= $timeStamp + $window; $ts++) + if (self::oath_hotp($binarySeed, $ts) == $key) + return true; + + return false; + + } + + /** + * Extracts the OTP from the SHA1 hash. + * @param binary $hash + * @return integer + **/ + public static function oath_truncate($hash) + { + $offset = ord($hash[19]) & 0xf; + + return ( + ((ord($hash[$offset+0]) & 0x7f) << 24 ) | + ((ord($hash[$offset+1]) & 0xff) << 16 ) | + ((ord($hash[$offset+2]) & 0xff) << 8 ) | + (ord($hash[$offset+3]) & 0xff) + ) % pow(10, self::otpLength); + } + + + +} + + +function util_array_trim(array &$array, $filter = false) +{ + array_walk_recursive($array, function (&$value) use ($filter) { + $value = trim($value); + if ($filter) { + $value = filter_var($value, FILTER_SANITIZE_STRING); + $value=strip_tags($value); + } + }); + + return $array; +} + + +?> + + + Token finder + + +

TOKEN2 TOKEN-Detect

+

A tool to identify a token by checking/comparing the current OTP
against a list of shared secrets/seed hashes

+
To be used if the token cannot be identified by its serial number, or if the serial number is wrongly attributed
+ +
+ $value) { + $key = explode(" ", $value); + + $detected="OTP does not match any of the seeds. Please check the key or increase the offset. "; +$offsettest=intval($_POST['otptestoffset']); + + $TimeStamp = Google2FA::get_timestamp() ; + if ($_POST['type']=="base32" ) { + $secretkey = Google2FA::base32_decode($key[1]); } + if ($_POST['type']=="hex" ) { + $secretkey = $key[1] ; } + + +for ($x = -$offsettest; $x <= $offsettest ; $x++) { + if ( intval($_POST['otptest'])==intval(Google2FA::oath_hotp($secretkey, $TimeStamp+$x)) ) { + + $detected= " Detected serial number $key[0] at offset $x "; + + + + } + +} + + } + + echo "

Result:


".$detected."

"; + } + + ?>
+
+ Serial+Seeds (separated by space, one per line )
example: "21312312312 JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"
+

+ Seed format     HEX Base32
+
+
+ + Current OTP
+
+ Offset    



+ + +
+ + \ No newline at end of file