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; +} + + +?> + +
+