%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/apps/twofactor_totp/vendor/rullzer/easytotp/tests/ |
Current File : /www/varak.net/nextcloud.varak.net/apps/twofactor_totp/vendor/rullzer/easytotp/tests/TOTPTest.php |
<?php declare(strict_types=1); /** * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> * * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace EasyTOTP\Tests; use EasyTOTP\TimeService; use EasyTOTP\TOTP; use EasyTOTP\TOTPInterface; use EasyTOTP\TOTPInvalidResultInterface; use EasyTOTP\TOTPValidResultInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** * Otp test case. */ class TOTPTest extends TestCase { /** @var string */ private $secret = "12345678901234567890"; /** @var TimeService|MockObject */ private $timeService; /** * Prepares the environment before running a test. */ protected function setUp(): void { parent::setUp(); $this->timeService = $this->createMock(TimeService::class); } /** * Invalid counter values for tests */ public function totpTestValues() { return [ [59, '94287082', TOTPInterface::HASH_SHA1, 1], [59, '46119246', TOTPInterface::HASH_SHA256, 1], [59, '90693936', TOTPInterface::HASH_SHA512, 1], [1111111109, '07081804', TOTPInterface::HASH_SHA1, 37037036], [1111111109, '68084774', TOTPInterface::HASH_SHA256, 37037036], [1111111109, '25091201', TOTPInterface::HASH_SHA512, 37037036], [1111111111, '14050471', TOTPInterface::HASH_SHA1, 37037037], [1111111111, '67062674', TOTPInterface::HASH_SHA256, 37037037], [1111111111, '99943326', TOTPInterface::HASH_SHA512, 37037037], [1234567890, '89005924', TOTPInterface::HASH_SHA1, 41152263], [1234567890, '91819424', TOTPInterface::HASH_SHA256, 41152263], [1234567890, '93441116', TOTPInterface::HASH_SHA512, 41152263], [2000000000, '69279037', TOTPInterface::HASH_SHA1, 66666666], [2000000000, '90698825', TOTPInterface::HASH_SHA256, 66666666], [2000000000, '38618901', TOTPInterface::HASH_SHA512, 66666666], [20000000000, '65353130', TOTPInterface::HASH_SHA1, 666666666], [20000000000, '77737706', TOTPInterface::HASH_SHA256, 666666666], [20000000000, '47863826', TOTPInterface::HASH_SHA512, 666666666], ]; } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction */ public function testTOTPRFC(int $time, string $otp, string $hashFunction) { $this->timeService->method('getTime') ->willReturn($time); $totp = new TOTP( $this->prepareSecret($this->prepareSecret($this->secret, $hashFunction), $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 0); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction */ public function testTimeDriftBack(int $time, string $otp, string $hashFunction) { $this->timeService->method('getTime') ->willReturn($time-30); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction * @param int $counter */ public function testTimeDriftForward(int $time, string $otp, string $hashFunction, int $counter) { $this->timeService->method('getTime') ->willReturn($time+30); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); $this->assertSame($counter, $result->getCounter()); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction * @param int $counter */ public function testTimeDriftOnlyForwardFails(int $time, string $otp, string $hashFunction, int $counter) { $this->timeService->method('getTime') ->willReturn($time); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1, $counter+1); $this->assertInstanceOf(TOTPInvalidResultInterface::class, $result); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction * @param int $counter */ public function testTimeDriftOnlyForwardSuccess(int $time, string $otp, string $hashFunction, int $counter) { $this->timeService->method('getTime') ->willReturn($time); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1, $counter-1); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); $this->assertSame($counter, $result->getCounter()); $this->assertSame(0, $result->getDrift()); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction * @param int $counter */ public function testTimeDriftClockSlow(int $time, string $otp, string $hashFunction, int $counter) { $this->timeService->method('getTime') ->willReturn($time+30); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); $this->assertSame($counter, $result->getCounter()); $this->assertSame(-1, $result->getDrift()); } /** * @dataProvider totpTestValues * * @param int $time * @param string $otp * @param string $hashFunction * @param int $counter */ public function testTimeDriftClockFase(int $time, string $otp, string $hashFunction, int $counter) { $this->timeService->method('getTime') ->willReturn($time-30); $totp = new TOTP( $this->prepareSecret($this->secret, $hashFunction), 30, 8, 0, $hashFunction, $this->timeService); $result = $totp->verify($otp, 1); $this->assertInstanceOf(TOTPValidResultInterface::class, $result); $this->assertSame($counter, $result->getCounter()); $this->assertSame(1, $result->getDrift()); } private function prepareSecret(string $secret, string $hashFunction) { if ($hashFunction === TOTPInterface::HASH_SHA1) { $secretLength = 20; } else if ($hashFunction === TOTPInterface::HASH_SHA256) { $secretLength = 32; } else if ($hashFunction === TOTPInterface::HASH_SHA512) { $secretLength = 64; } else { $this->fail('Invalid hash function'); } while(strlen($secret) < $secretLength) { $secret .= $secret; } $secret = substr($secret, 0, $secretLength); return $secret; } }