From a55a09b05bf3dd65a8e8e6ed8890165ba2c91a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Kooman?= Date: Fri, 3 Mar 2017 17:37:05 +0100 Subject: [PATCH 1/3] use paragonie/random_compat it is better to use random_compat for CSRPNG, see https://paragonie.com/blog/2016/05/how-generate-secure-random-numbers-in-various-programming-languages#php-csprng --- composer.json | 6 ++---- src/GoogleAuthenticator.php | 30 ++---------------------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index e434580..f6ffeda 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ ], "require": { "php": ">=5.4.0", - "christian-riesen/base32": "^1.0" + "christian-riesen/base32": "^1.0", + "paragonie/random_compat": "^1|^2" }, "require-dev": { "phpunit/phpunit": "^4.8" @@ -30,9 +31,6 @@ "Otp\\Tests\\": "tests/" } }, - "suggest": { - "paragonie/random_compat": "Optional polyfill for a more secure random generator for pre PHP7 versions" - }, "extra": { "branch-alias": { "dev-master": "2.x-dev" diff --git a/src/GoogleAuthenticator.php b/src/GoogleAuthenticator.php index 0925510..8e90532 100644 --- a/src/GoogleAuthenticator.php +++ b/src/GoogleAuthenticator.php @@ -161,7 +161,7 @@ public static function generateRandom($length = 16) $string = ''; for ($i = 0; $i < $length; $i++) { - $string .= $keys[self::getRand()]; + $string .= $keys[random_int(0, 31)]; } return $string; @@ -187,7 +187,7 @@ public static function generateRecoveryCodes($count = 1, $length = 9) // Generate codes $code = ''; for ($i = 1; $i <= $length; $i++) { - $code .= self::getRand(9); + $code .= random_int(0, 9); } // To make sure no duplicates get in @@ -198,30 +198,4 @@ public static function generateRecoveryCodes($count = 1, $length = 9) return $codes; } - - /** - * Get random number - * - * @return integer Random number between 0 and 31 (including) - */ - private static function getRand($max = 31) - { - if (function_exists('random_int')) { - // Uses either the PHP7 internal function or the polyfill if present - return random_int(0, $max); - } elseif (function_exists('openssl_random_pseudo_bytes')) { - // For those not wanting either PHP7 or the polyfill, this works well enough - $bytes = openssl_random_pseudo_bytes(2); - $number = hexdec(bin2hex($bytes)); - - if ($number > $max) { - $number = $number % ($max + 1); - } - - return $number; - } else { - // And last case, this does the trick too - return mt_rand(0, $max); - } - } } From a149b0c420dc19dc35a91fb45ea1fc06ecb4d811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Kooman?= Date: Thu, 16 Mar 2017 15:43:03 +0100 Subject: [PATCH 2/3] switch to paragonie/constant_time_encoding for Base32 handling --- README.md | 12 +++++------- composer.json | 2 +- example/index.php | 6 +++--- src/GoogleAuthenticator.php | 2 ++ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d724f64..074d2d3 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,7 @@ Usage use Otp\Otp; use Otp\GoogleAuthenticator; - -// Seperate class, see https://github.com/ChristianRiesen/base32, requirement for this one -use Base32\Base32; +use ParagonIE\ConstantTime\Encoding; // Get a Pseudo Secret // Defaults to 16 characters @@ -48,7 +46,7 @@ $otp = new Otp(); // Assuming this is present and sanitized // Allows for a 1 code time drift by default // Third parameter can alter that behavior -if ($otp->checkTotp(Base32::decode($secret), $key)) { +if ($otp->checkTotp(Encoding::base32Decode($secret), $key)) { // Correct key // IMPORTANT! Note this key as being used // so nobody could launch a replay attack. @@ -59,7 +57,7 @@ if ($otp->checkTotp(Base32::decode($secret), $key)) { } // Just to create a key for display (testing) -$key = $otp->totp(Base32::decode($secret)); +$key = $otp->totp(Encoding::base32Decode($secret)); ``` @@ -77,7 +75,7 @@ Static function class to generate a correct url for the QR code, so you can easy There are also older open source versions of the Google Authenticator app for both [iPhone](https://github.com/google/google-authenticator) and [Android](https://github.com/google/google-authenticator-android) -This helper class uses the random_int function from PHP7, or the polyfill method from [paragonie/random_compat](https://packagist.org/packages/paragonie/random_compat) if present and falls back on other (less "secure") random generators. +This helper class uses the random_int function from PHP7, or the polyfill method from [paragonie/random_compat](https://packagist.org/packages/paragonie/random_compat) if present. About ===== @@ -87,7 +85,7 @@ Requirements PHP 5.4.x+ -Uses [Base32 class](https://github.com/ChristianRiesen/base32). +Uses [paragonie/random_compat](https://github.com/paragonie/random_compat) and [paragonie/constant_time_encoding](https://github.com/paragonie/constant_time_encoding). If you want to run the tests, PHPUnit 3.6 or up is required. diff --git a/composer.json b/composer.json index f6ffeda..b3e78c3 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": ">=5.4.0", - "christian-riesen/base32": "^1.0", + "paragonie/constant_time_encoding": "^1|^2", "paragonie/random_compat": "^1|^2" }, "require-dev": { diff --git a/example/index.php b/example/index.php index 4da362c..e5e9b7f 100644 --- a/example/index.php +++ b/example/index.php @@ -6,7 +6,7 @@ use Otp\Otp; use Otp\GoogleAuthenticator; -use Base32\Base32; +use ParagonIE\ConstantTime\Encoding; // Getting a secret, either by generating or from storage // DON'T use sessions as storage for this in production!!! @@ -25,7 +25,7 @@ // To use it in totp though we need to decode it into the original $otp = new Otp(); -$currentTotp = $otp->totp(Base32::decode($secret)); +$currentTotp = $otp->totp(Encoding::base32DecodeUpper($secret)); $qrCode = GoogleAuthenticator::getQrCodeUrl('totp', 'otpsample@cr', $secret); $keyUri = GoogleAuthenticator::getKeyUri('totp', 'otpsample@cr', $secret); @@ -79,7 +79,7 @@ if (strlen($key) == 6) { // Remember that the secret is a base32 string that needs decoding // to use it here! - if ($otp->checkTotp(Base32::decode($secret), $key)) { + if ($otp->checkTotp(Encoding::base32DecodeUpper($secret), $key)) { echo 'Key correct!'; // Add here something that makes note of this key and will not allow // the use of it, for this user for the next 2 minutes. This way you diff --git a/src/GoogleAuthenticator.php b/src/GoogleAuthenticator.php index 8e90532..48b0a6f 100644 --- a/src/GoogleAuthenticator.php +++ b/src/GoogleAuthenticator.php @@ -2,6 +2,8 @@ namespace Otp; +use ParagonIE\ConstantTime\Encoding; + /** * Google Authenticator * From 34bcbead1414383a0f2fc98fabf98acd2b9a3ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Kooman?= Date: Thu, 16 Mar 2017 15:44:33 +0100 Subject: [PATCH 3/3] small README update --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 074d2d3..4f02bf3 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,7 @@ Class GoogleAuthenticator Static function class to generate a correct url for the QR code, so you can easy scan it with your device. Google Authenticator is avaiaible as application for iPhone and Android. This removes the burden to create such an app from the developers of websites by using this set of classes. -There are also older open source versions of the Google Authenticator app for both [iPhone](https://github.com/google/google-authenticator) and [Android](https://github.com/google/google-authenticator-android) - -This helper class uses the random_int function from PHP7, or the polyfill method from [paragonie/random_compat](https://packagist.org/packages/paragonie/random_compat) if present. +There are also older open source versions of the Google Authenticator app for both [iPhone](https://github.com/google/google-authenticator) and [Android](https://github.com/google/google-authenticator-android). About =====