From c94fcd83d81a091bdde89a2390c6636d09b1eb78 Mon Sep 17 00:00:00 2001 From: RobThree Date: Wed, 2 Dec 2015 16:38:20 +0100 Subject: [PATCH] * Added new (PHP7+) CSRNGProvider (uses random_bytes) * Added a bunch basic of unittests for the RNG's * QRicketProvider and QRServerProvider now throw on invalid MIME-types * TwoFactorAuth now first tries to use CSRNGProvider before any of the other RNG providers --- TwoFactorAuth.phpproj | 1 + composer.json | 2 +- lib/Providers/Qr/QRServerProvider.php | 1 + lib/Providers/Qr/QRicketProvider.php | 1 + lib/Providers/Rng/CSRNGProvider.php | 14 ++++++ lib/TwoFactorAuth.php | 4 +- tests/TwoFactorAuthTest.php | 69 ++++++++++++++++++++++++--- 7 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 lib/Providers/Rng/CSRNGProvider.php diff --git a/TwoFactorAuth.phpproj b/TwoFactorAuth.phpproj index c17df88..76a1830 100644 --- a/TwoFactorAuth.phpproj +++ b/TwoFactorAuth.phpproj @@ -30,6 +30,7 @@ + diff --git a/composer.json b/composer.json index c73bb07..43fa999 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "robthree/twofactorauth", "description": "Two Factor Authentication", - "version": "1.3", + "version": "1.4", "type": "library", "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ], "homepage": "https://github.com/RobThree/TwoFactorAuth", diff --git a/lib/Providers/Qr/QRServerProvider.php b/lib/Providers/Qr/QRServerProvider.php index 87717f1..2d889f9 100644 --- a/lib/Providers/Qr/QRServerProvider.php +++ b/lib/Providers/Qr/QRServerProvider.php @@ -43,6 +43,7 @@ class QRServerProvider extends BaseHTTPQRCodeProvider case 'eps': return 'application/postscript'; } + throw new QRException(sprintf('Unknown MIME-type: %s', $this->format)); } public function getQRCodeImage($qrtext, $size) diff --git a/lib/Providers/Qr/QRicketProvider.php b/lib/Providers/Qr/QRicketProvider.php index b6aed5a..e2f404b 100644 --- a/lib/Providers/Qr/QRicketProvider.php +++ b/lib/Providers/Qr/QRicketProvider.php @@ -33,6 +33,7 @@ class QRicketProvider extends BaseHTTPQRCodeProvider case 'j': return 'image/jpeg'; } + throw new QRException(sprintf('Unknown MIME-type: %s', $this->format)); } public function getQRCodeImage($qrtext, $size) diff --git a/lib/Providers/Rng/CSRNGProvider.php b/lib/Providers/Rng/CSRNGProvider.php new file mode 100644 index 0000000..8dba7fc --- /dev/null +++ b/lib/Providers/Rng/CSRNGProvider.php @@ -0,0 +1,14 @@ +getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars + $tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars } /** @@ -155,7 +155,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase */ public function testGetCodeThrowsOnInvalidBase32String2() { $tfa = new TwoFactorAuth('Test'); - $result = $tfa->getCode('mzxw6==='); //Lowercase + $tfa->getCode('mzxw6==='); //Lowercase } public function testKnownBase32DecodeTestVectors() { @@ -242,7 +242,62 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase $this->assertEquals('47863826', $tfa->getCode($secret, 20000000000)); } + /** + * @requires function random_bytes + */ + public function testCSRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\CSRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function hash_algos + * @requires function hash + */ + public function testHashRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\HashRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(false, $rng->isCryptographicallySecure()); + } + /** + * @requires function mcrypt_create_iv + */ + public function testMCryptRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function openssl_random_pseudo_bytes + */ + public function testStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(true); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } + + /** + * @requires function openssl_random_pseudo_bytes + */ + public function testNonStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() { + $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(false); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(false, $rng->isCryptographicallySecure()); + } + + + private function getRngTestLengths() { + return array(1, 16, 32, 256); + } + private function DecodeDataUri($datauri) { if (preg_match('/data:(?P[\w\.\-\/]+);(?P\w+),(?P.*)/', $datauri, $m) === 1) { return array(