diff --git a/RobThree/TwoFactorAuth/Providers/BaseHTTPQRCodeProvider.php b/RobThree/TwoFactorAuth/Providers/Qr/BaseHTTPQRCodeProvider.php
similarity index 93%
rename from RobThree/TwoFactorAuth/Providers/BaseHTTPQRCodeProvider.php
rename to RobThree/TwoFactorAuth/Providers/Qr/BaseHTTPQRCodeProvider.php
index f29265d..7cf2d82 100644
--- a/RobThree/TwoFactorAuth/Providers/BaseHTTPQRCodeProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Qr/BaseHTTPQRCodeProvider.php
@@ -1,6 +1,6 @@
verifyssl = $verifyssl;
diff --git a/RobThree/TwoFactorAuth/Providers/IQRCodeProvider.php b/RobThree/TwoFactorAuth/Providers/Qr/IQRCodeProvider.php
similarity index 72%
rename from RobThree/TwoFactorAuth/Providers/IQRCodeProvider.php
rename to RobThree/TwoFactorAuth/Providers/Qr/IQRCodeProvider.php
index 6aeb856..8a0840a 100644
--- a/RobThree/TwoFactorAuth/Providers/IQRCodeProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Qr/IQRCodeProvider.php
@@ -1,6 +1,6 @@
verifyssl = $verifyssl;
diff --git a/RobThree/TwoFactorAuth/Providers/QRicketProvider.php b/RobThree/TwoFactorAuth/Providers/Qr/QRicketProvider.php
similarity index 96%
rename from RobThree/TwoFactorAuth/Providers/QRicketProvider.php
rename to RobThree/TwoFactorAuth/Providers/Qr/QRicketProvider.php
index 2356235..bcd5e89 100644
--- a/RobThree/TwoFactorAuth/Providers/QRicketProvider.php
+++ b/RobThree/TwoFactorAuth/Providers/Qr/QRicketProvider.php
@@ -1,6 +1,6 @@
algorithm = $algorithm;
+ }
+
+ public function getRandomBytes($bytecount) {
+ $result = array();
+ for ($i = 0; $i < $bytecount; $i++) {
+ $hash = hash($this->algorithm, $hash.mt_rand(), true);
+ array_push($result, $hash[mt_rand(0, sizeof($hash))]);
+ }
+ return $result;
+ }
+}
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php
new file mode 100644
index 0000000..d401827
--- /dev/null
+++ b/RobThree/TwoFactorAuth/Providers/Rng/IRNGProvider.php
@@ -0,0 +1,8 @@
+source = $source;
+ }
+
+ public function getRandomBytes($bytecount) {
+ $result = mcrypt_create_iv($bytecount, $this->source);
+ if ($result === false)
+ throw new RNGException('mcrypt_create_iv returned an invalid value');
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php b/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php
new file mode 100644
index 0000000..edab2cd
--- /dev/null
+++ b/RobThree/TwoFactorAuth/Providers/Rng/OpenSSLRNGProvider.php
@@ -0,0 +1,21 @@
+requirestrong = $requirestrong;
+ }
+
+ public function getRandomBytes($bytecount) {
+ $result = openssl_random_pseudo_bytes($bytecount, $crypto_strong);
+ if ($this->requirestrong && ($crypto_strong === false))
+ throw new RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value');
+ if ($result === false)
+ throw new RNGException('openssl_random_pseudo_bytes returned an invalid value');
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/RobThree/TwoFactorAuth/Providers/Rng/RNGException.php b/RobThree/TwoFactorAuth/Providers/Rng/RNGException.php
new file mode 100644
index 0000000..882d7f7
--- /dev/null
+++ b/RobThree/TwoFactorAuth/Providers/Rng/RNGException.php
@@ -0,0 +1,11 @@
+issuer = $issuer;
@@ -32,14 +33,31 @@ class TwoFactorAuth
throw new Exception('Unsupported algorithm: ' . $algorithm);
$this->algorithm = $algorithm;
+ // Set default QR Code provider if none was specified
if ($qrcodeprovider==null)
- $qrcodeprovider = new Providers\GoogleQRCodeProvider();
+ $qrcodeprovider = new Providers\Qr\GoogleQRCodeProvider();
- if (!($qrcodeprovider instanceof Providers\IQRCodeProvider))
+ if (!($qrcodeprovider instanceof Providers\Qr\IQRCodeProvider))
throw new Exception('QRCodeProvider must implement IQRCodeProvider');
$this->qrcodeprovider = $qrcodeprovider;
+ // Try to find best available RNG provider if none was specified
+ if ($rngprovider==null) {
+ if (function_exists('mcrypt_create_iv')) {
+ $rngprovider = new Providers\Rng\MCryptRNGProvider();
+ } elseif (function_exists('openssl_random_pseudo_bytes')) {
+ $rngprovider = new Providers\Rng\OpenSSLRNGProvider();
+ } else {
+ $rngprovider = new Providers\Rng\HashRNGProvider();
+ }
+ }
+
+ if (!($rngprovider instanceof Providers\Rng\IRNGProvider))
+ throw new Exception('RNGProvider must implement IRNGProvider');
+
+ $this->rngprovider = $rngprovider;
+
self::$_base32 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=');
self::$_base32lookup = array_flip(self::$_base32);
}
@@ -51,7 +69,7 @@ class TwoFactorAuth
{
$secret = '';
$bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
- $rnd = openssl_random_pseudo_bytes($bytes);
+ $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
return $secret;
diff --git a/TwoFactorAuth.phpproj b/TwoFactorAuth.phpproj
index ca8028e..f9f9b3d 100644
--- a/TwoFactorAuth.phpproj
+++ b/TwoFactorAuth.phpproj
@@ -24,11 +24,17 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -37,6 +43,8 @@
+
+