Compare commits

...

3 Commits

Author SHA1 Message Date
RobThree f546c73537 * Added CSRNGProvider to requires in unittestfile. 2015-12-02 16:40:18 +01:00
RobThree c94fcd83d8 * 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
2015-12-02 16:38:20 +01:00
Rob Janssen 856167c950 Update README.md 2015-11-21 01:09:38 +01:00
8 changed files with 85 additions and 10 deletions
+1 -1
View File
@@ -81,7 +81,7 @@ When outputting a QR-code you can choose a `$label` for the user (which, when en
### Step 2: Verify secret shared key
When the code is added to the app, the app will be ready to start generating codes which 'expire' each '`$period`' number of seconds. To make sure the secret was entered, or scanned, correctly you need to verify this by having the user enter a generated code. To check if the generated code is valid you call the `verifyCode()` method:
When the shared secret is added to the app, the app will be ready to start generating codes which 'expire' each '`$period`' number of seconds. To make sure the secret was entered, or scanned, correctly you need to verify this by having the user enter a generated code. To check if the generated code is valid you call the `verifyCode()` method:
````php
// Verify code
+1
View File
@@ -30,6 +30,7 @@
<Compile Include="lib\Providers\Qr\QRException.php" />
<Compile Include="lib\Providers\Qr\QRicketProvider.php" />
<Compile Include="lib\Providers\Qr\QRServerProvider.php" />
<Compile Include="lib\Providers\Rng\CSRNGProvider.php" />
<Compile Include="lib\Providers\Rng\IRNGProvider.php" />
<Compile Include="lib\Providers\Rng\MCryptRNGProvider.php" />
<Compile Include="lib\Providers\Rng\OpenSSLRNGProvider.php" />
+1 -1
View File
@@ -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",
+1
View File
@@ -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)
+1
View File
@@ -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)
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace RobThree\Auth\Providers\Rng;
class CSRNGProvider implements IRNGProvider
{
public function getRandomBytes($bytecount) {
return random_bytes($bytecount); // PHP7+
}
public function isCryptographicallySecure() {
return true;
}
}
+3 -1
View File
@@ -45,7 +45,9 @@ class TwoFactorAuth
// Try to find best available RNG provider if none was specified
if ($rngprovider==null) {
if (function_exists('mcrypt_create_iv')) {
if (function_exists('random_bytes')) {
$rngprovider = new Providers\Rng\CSRNGProvider();
} elseif (function_exists('mcrypt_create_iv')) {
$rngprovider = new Providers\Rng\MCryptRNGProvider();
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$rngprovider = new Providers\Rng\OpenSSLRNGProvider();
+63 -7
View File
@@ -8,6 +8,7 @@ require_once 'lib/Providers/Qr/GoogleQRCodeProvider.php';
require_once 'lib/Providers/Rng/IRNGProvider.php';
require_once 'lib/Providers/Rng/RNGException.php';
require_once 'lib/Providers/Rng/CSRNGProvider.php';
require_once 'lib/Providers/Rng/MCryptRNGProvider.php';
require_once 'lib/Providers/Rng/OpenSSLRNGProvider.php';
require_once 'lib/Providers/Rng/HashRNGProvider.php';
@@ -24,7 +25,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorThrowsOnInvalidDigits() {
$tfa = new TwoFactorAuth('Test', 0);
new TwoFactorAuth('Test', 0);
}
/**
@@ -32,7 +33,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorThrowsOnInvalidPeriod() {
$tfa = new TwoFactorAuth('Test', 6, 0);
new TwoFactorAuth('Test', 6, 0);
}
/**
@@ -40,7 +41,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorThrowsOnInvalidAlgorithm() {
$tfa = new TwoFactorAuth('Test', 6, 30, 'xxx');
new TwoFactorAuth('Test', 6, 30, 'xxx');
}
/**
@@ -48,7 +49,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorThrowsOnQrProviderNotImplementingInterface() {
$tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', new stdClass());
new TwoFactorAuth('Test', 6, 30, 'sha1', new stdClass());
}
/**
@@ -56,7 +57,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorThrowsOnRngProviderNotImplementingInterface() {
$tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, new stdClass());
new TwoFactorAuth('Test', 6, 30, 'sha1', null, new stdClass());
}
public function testGetCodeReturnsCorrectResults() {
@@ -147,7 +148,7 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
*/
public function testGetCodeThrowsOnInvalidBase32String1() {
$tfa = new TwoFactorAuth('Test');
$result = $tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars
$tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars
}
/**
@@ -155,7 +156,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 +243,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<mimetype>[\w\.\-\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
return array(