61 lines
1.2 KiB
PHP
61 lines
1.2 KiB
PHP
<?php
|
|
/**
|
|
* Class TOTP
|
|
*
|
|
* @created 15.06.2023
|
|
* @author smiley <smiley@chillerlan.net>
|
|
* @copyright 2023 smiley
|
|
* @license MIT
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace chillerlan\Authenticator\Authenticators;
|
|
|
|
use SensitiveParameter;
|
|
use function floor;
|
|
use function hash_equals;
|
|
use function time;
|
|
|
|
/**
|
|
* @link https://tools.ietf.org/html/rfc6238
|
|
*/
|
|
class TOTP extends HOTP{
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getCounter(int|null $data = null):int{
|
|
$data ??= time();
|
|
|
|
if($this->options->useLocalTime === false){
|
|
$data = $this->getServerTime();
|
|
}
|
|
|
|
return (int)floor(($data + $this->options->time_offset) / $this->options->period);
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function verify(#[SensitiveParameter] string $otp, int|null $data = null):bool{
|
|
$limit = $this->options->adjacent;
|
|
|
|
if($limit === 0){
|
|
return parent::verify($otp, $data); // @codeCoverageIgnore
|
|
}
|
|
|
|
$timeslice = $this->getCounter($data);
|
|
// phpcs:ignore
|
|
for($i = -$limit; $i <= $limit; $i++){
|
|
$hash = $this->getHMAC($timeslice + $i);
|
|
$code = $this->getOTP($this->getCode($hash));
|
|
|
|
if(hash_equals($code, $otp)){
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|