Copybara bot | be50d49 | 2023-11-30 00:16:42 +0100 | [diff] [blame] | 1 | <?php |
| 2 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | // you may not use this file except in compliance with the License. |
| 4 | // You may obtain a copy of the License at |
| 5 | // |
| 6 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | // |
| 8 | // Unless required by applicable law or agreed to in writing, software |
| 9 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | // See the License for the specific language governing permissions and |
| 12 | // limitations under the License. |
| 13 | |
| 14 | |
| 15 | include_once("FixedByteNotation.php"); |
| 16 | |
| 17 | |
| 18 | class GoogleAuthenticator { |
| 19 | static $PASS_CODE_LENGTH = 6; |
| 20 | static $PIN_MODULO; |
| 21 | static $SECRET_LENGTH = 20; |
| 22 | |
| 23 | public function __construct() { |
| 24 | self::$PIN_MODULO = pow(10, self::$PASS_CODE_LENGTH); |
| 25 | } |
| 26 | |
| 27 | public function checkCode($secret,$code) { |
| 28 | $time = floor(time() / 30); |
| 29 | for ( $i = -1; $i <= 1; $i++) { |
| 30 | |
| 31 | if ($this->getCode($secret,$time + $i) == $code) { |
| 32 | return true; |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | return false; |
| 37 | |
| 38 | } |
| 39 | |
| 40 | public function getCode($secret,$time = null) { |
| 41 | |
| 42 | if (!$time) { |
| 43 | $time = floor(time() / 30); |
| 44 | } |
| 45 | $base32 = new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE); |
| 46 | $secret = $base32->decode($secret); |
| 47 | |
| 48 | $time = pack("N", $time); |
| 49 | $time = str_pad($time,8, chr(0), STR_PAD_LEFT); |
| 50 | |
| 51 | $hash = hash_hmac('sha1',$time,$secret,true); |
| 52 | $offset = ord(substr($hash,-1)); |
| 53 | $offset = $offset & 0xF; |
| 54 | |
| 55 | $truncatedHash = self::hashToInt($hash, $offset) & 0x7FFFFFFF; |
| 56 | $pinValue = str_pad($truncatedHash % self::$PIN_MODULO,6,"0",STR_PAD_LEFT);; |
| 57 | return $pinValue; |
| 58 | } |
| 59 | |
| 60 | protected function hashToInt($bytes, $start) { |
| 61 | $input = substr($bytes, $start, strlen($bytes) - $start); |
| 62 | $val2 = unpack("N",substr($input,0,4)); |
| 63 | return $val2[1]; |
| 64 | } |
| 65 | |
| 66 | public function getUrl($user, $hostname, $secret) { |
| 67 | $url = sprintf("otpauth://totp/%s@%s?secret=%s", $user, $hostname, $secret); |
| 68 | $encoder = "https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl="; |
| 69 | $encoderURL = sprintf( "%sotpauth://totp/%s@%s&secret=%s",$encoder, $user, $hostname, $secret); |
| 70 | |
| 71 | return $encoderURL; |
| 72 | |
| 73 | } |
| 74 | |
| 75 | public function generateSecret() { |
| 76 | $secret = ""; |
| 77 | for($i = 1; $i<= self::$SECRET_LENGTH;$i++) { |
| 78 | $c = random_int(0,255); |
| 79 | $secret .= pack("c",$c); |
| 80 | } |
| 81 | $base32 = new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE); |
| 82 | return $base32->encode($secret); |
| 83 | |
| 84 | |
| 85 | } |
| 86 | |
| 87 | } |