diff --git a/RobThree/TwoFactorAuth/Providers/Rng/HashRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/HashRNGProvider.php
index 8a7b06d..645c7dc 100644
--- a/RobThree/TwoFactorAuth/Providers/Rng/HashRNGProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Rng/HashRNGProvider.php
@@ -13,11 +13,16 @@ class HashRNGProvider implements IRNGProvider
}
public function getRandomBytes($bytecount) {
- $result = array();
+ $result = '';
+ $hash = mt_rand();
for ($i = 0; $i < $bytecount; $i++) {
$hash = hash($this->algorithm, $hash.mt_rand(), true);
- array_push($result, $hash[mt_rand(0, sizeof($hash))]);
+ $result .= $hash[mt_rand(0, sizeof($hash))];
}
return $result;
}
+
+ public function isCryptographicallySecure() {
+ return false;
+ }
}
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php
index d401827..44bb9d5 100644
--- a/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php
@@ -5,4 +5,5 @@ namespace RobThree\TwoFactorAuth\Providers\Rng;
interface IRNGProvider
{
public function getRandomBytes($bytecount);
+ public function isCryptographicallySecure();
}
\ No newline at end of file
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/MCryptRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/MCryptRNGProvider.php
index 8618ca3..b97be1a 100644
--- a/RobThree/TwoFactorAuth/Providers/Rng/MCryptRNGProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Rng/MCryptRNGProvider.php
@@ -16,4 +16,8 @@ class MCryptRNGProvider implements IRNGProvider
throw new RNGException('mcrypt_create_iv returned an invalid value');
return $result;
}
+
+ public function isCryptographicallySecure() {
+ return true;
+ }
}
\ No newline at end of file
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php
index edab2cd..2105136 100644
--- a/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php
@@ -18,4 +18,8 @@ class OpenSSLRNGProvider implements IRNGProvider
throw new RNGException('openssl_random_pseudo_bytes returned an invalid value');
return $result;
}
+
+ public function isCryptographicallySecure() {
+ return $this->requirestrong;
+ }
}
\ No newline at end of file
diff --git a/RobThree/TwoFactorAuth/TwoFactorAuth.php b/RobThree/TwoFactorAuth/TwoFactorAuth.php
index 08fa1be..4273bbb 100644
--- a/RobThree/TwoFactorAuth/TwoFactorAuth.php
+++ b/RobThree/TwoFactorAuth/TwoFactorAuth.php
@@ -21,16 +21,16 @@ class TwoFactorAuth
$this->issuer = $issuer;
if (!is_int($digits) || $digits <= 0)
- throw new Exception('Digits must be int > 0');
+ throw new TwoFactorAuthException('Digits must be int > 0');
$this->digits = $digits;
if (!is_int($period) || $period <= 0)
- throw new Exception('Period must be int > 0');
+ throw new TwoFactorAuthException('Period must be int > 0');
$this->period = $period;
$algorithm = strtolower(trim($algorithm));
if (!in_array($algorithm, self::$_supportedalgos))
- throw new Exception('Unsupported algorithm: ' . $algorithm);
+ throw new TwoFactorAuthException('Unsupported algorithm: ' . $algorithm);
$this->algorithm = $algorithm;
// Set default QR Code provider if none was specified
@@ -38,7 +38,7 @@ class TwoFactorAuth
$qrcodeprovider = new Providers\Qr\GoogleQRCodeProvider();
if (!($qrcodeprovider instanceof Providers\Qr\IQRCodeProvider))
- throw new Exception('QRCodeProvider must implement IQRCodeProvider');
+ throw new TwoFactorAuthException('QRCodeProvider must implement IQRCodeProvider');
$this->qrcodeprovider = $qrcodeprovider;
@@ -54,7 +54,7 @@ class TwoFactorAuth
}
if (!($rngprovider instanceof Providers\Rng\IRNGProvider))
- throw new Exception('RNGProvider must implement IRNGProvider');
+ throw new TwoFactorAuthException('RNGProvider must implement IRNGProvider');
$this->rngprovider = $rngprovider;
@@ -65,10 +65,12 @@ class TwoFactorAuth
/**
* Create a new secret
*/
- public function createSecret($bits = 80)
+ public function createSecret($bits = 80, $requirecryptosecure = true)
{
$secret = '';
$bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
+ if ($requirecryptosecure && !$this->rngprovider->isCryptographicallySecure())
+ throw new TwoFactorAuthException('RNG provider is not cryptographically secure');
$rnd = $this->rngprovider->getRandomBytes($bytes);
for ($i = 0; $i < $bytes; $i++)
$secret .= self::$_base32[ord($rnd[$i]) & 31]; //Mask out left 3 bits for 0-31 values
@@ -112,7 +114,7 @@ class TwoFactorAuth
public function getQRCodeImageAsDataUri($label, $secret, $size = 200)
{
if (!is_int($size) || $size < 0)
- throw new Exception('Size must be int > 0');
+ throw new TwoFactorAuthException('Size must be int > 0');
return 'data:'
. $this->qrcodeprovider->getMimeType()
diff --git a/RobThree/TwoFactorAuth/TwoFactorAuthException.php b/RobThree/TwoFactorAuth/TwoFactorAuthException.php
new file mode 100644
index 0000000..9de9d3a
--- /dev/null
+++ b/RobThree/TwoFactorAuth/TwoFactorAuthException.php
@@ -0,0 +1,11 @@
+
+