157 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php namespace App\Support;
 | |
| 
 | |
| /**
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| use App\Support\Base32;
 | |
| 
 | |
| class Totp
 | |
| {
 | |
|     protected $passCodeLength;
 | |
|     protected $secretLength;
 | |
|     protected $pinModulo;
 | |
| 
 | |
|     /**
 | |
|      * @param int $passCodeLength
 | |
|      * @param int $secretLength
 | |
|      */
 | |
|     public function __construct($passCodeLength = 6, $secretLength = 10)
 | |
|     {
 | |
|         $this->passCodeLength = $passCodeLength;
 | |
|         $this->secretLength   = $secretLength;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * get TimeStamp
 | |
|      * period.
 | |
|      * @return integer
 | |
|      **/
 | |
|     public function getTimeStamp()
 | |
|     {
 | |
|         return floor(time() / 30);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $secret
 | |
|      * @param $code
 | |
|      * @return bool
 | |
|      */
 | |
|     public function generateByTime($secret, $code)
 | |
|     {
 | |
|         for ($i = -1; $i <= 1; $i++) {
 | |
|             if ($this->generateByCounter($secret, $this->getTimeStamp() + $i) == $code) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $secret
 | |
|      * @param null $time
 | |
|      * @return string
 | |
|      */
 | |
|     public function generateByCounter($secret, $time = null)
 | |
|     {
 | |
|         if ($time === null) {
 | |
|             $time = $this->getTimeStamp();
 | |
|         }
 | |
| 
 | |
|         $secret = Base32::decode($secret);
 | |
| 
 | |
|         $time = pack("N", $time);
 | |
|         $time = str_pad($time, 8, chr(0), STR_PAD_LEFT);
 | |
| 
 | |
|         $hash = hash_hmac('sha1', $time, $secret, true);
 | |
|         $offset = ord(substr($hash, -1));
 | |
|         $offset = $offset & 0xF;
 | |
| 
 | |
|         $truncatedHash = self::hashToInt($hash, $offset) & 0x7FFFFFFF;
 | |
|         $pinValue = str_pad($truncatedHash % pow(10, $this->passCodeLength), $this->passCodeLength, "0", STR_PAD_LEFT);
 | |
| 
 | |
|         return $pinValue;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $bytes
 | |
|      * @param $start
 | |
|      * @return integer
 | |
|      */
 | |
|     protected static function hashToInt($bytes, $start)
 | |
|     {
 | |
|         $input = substr($bytes, $start, strlen($bytes) - $start);
 | |
|         $val2 = unpack("N", substr($input, 0, 4));
 | |
| 
 | |
|         return $val2[1];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $user
 | |
|      * @param string $hostname
 | |
|      * @param string $secret
 | |
|      * @return string
 | |
|      */
 | |
|     public function getURL($user, $hostname, $secret)
 | |
|     {
 | |
|         $encoderURL = sprintf("otpauth://totp/%s@%s%%3Fsecret%%3D%s", $user, $hostname, $secret);
 | |
|         return $encoderURL;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function generateSecret($secret = null)
 | |
|     {
 | |
|         if ($secret === null) {
 | |
|             $secret = '';
 | |
|             for ($i = 1; $i <= $this->secretLength; $i++) {
 | |
|                 $c = rand(0, 255);
 | |
|                 $secret .= pack("c", $c);
 | |
|             }
 | |
|         }
 | |
|         return Base32::encode($secret);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
| $secret = '2222222222222222';
 | |
| $code = "181419";
 | |
| 
 | |
| $g = new TimeAuthenticator();
 | |
| 
 | |
| print "Current Code is: ";
 | |
| print $g->generateByCounter($secret);
 | |
| 
 | |
| print "\n";
 | |
| 
 | |
| print "Check if $code is valid: ";
 | |
| 
 | |
| if ($g->generateByTime($secret, $code))
 | |
| {
 | |
|     print "YES \n";
 | |
| }
 | |
| else
 | |
| {
 | |
|     print "NO \n";
 | |
| }
 | |
| 
 | |
| $secret = $g->generateSecret();
 | |
| print "Get a new Secret: $secret \n";
 | |
| 
 | |
| print "The QR Code for this secret (to scan with the Google Authenticator App: \n";
 | |
| print $g->getURL('fvzone','gmail.com', $secret);
 | |
| print "\n";
 | |
| */
 |