From 07da71fd3476520df1b626aedb613124e91ed752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Mon, 30 Oct 2017 23:26:30 +0100 Subject: [PATCH 1/7] Added argon hashing support. --- src/Illuminate/Hashing/ArgonHasher.php | 161 ++++++++++++++++++ src/Illuminate/Hashing/HashManager.php | 38 +++++ .../Hashing/HashServiceProvider.php | 4 +- tests/Hashing/BcryptHasherTest.php | 18 -- tests/Hashing/HasherTest.php | 32 ++++ 5 files changed, 233 insertions(+), 20 deletions(-) create mode 100644 src/Illuminate/Hashing/ArgonHasher.php create mode 100644 src/Illuminate/Hashing/HashManager.php delete mode 100755 tests/Hashing/BcryptHasherTest.php create mode 100755 tests/Hashing/HasherTest.php diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php new file mode 100644 index 000000000000..16c5ef4240ba --- /dev/null +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -0,0 +1,161 @@ + $this->memory($options), + 'time_cost' => $this->time($options), + 'threads' => $this->processors($options) + ]); + + if ($hash === false) { + throw new RuntimeException('Bcrypt hashing not supported.'); + } + + return $hash; + } + + /** + * Check the given plain value against a hash. + * + * @param string $value + * @param string $hashedValue + * @param array $options + * @return bool + */ + public function check($value, $hashedValue, array $options = []) + { + if (strlen($hashedValue) === 0) { + return false; + } + + return password_verify($value, $hashedValue); + } + + /** + * Check if the given hash has been hashed using the given options. + * + * @param string $hashedValue + * @param array $options + * @return bool + */ + public function needsRehash($hashedValue, array $options = []) + { + return password_needs_rehash($hashedValue, PASSWORD_ARGON2I, [ + 'memory_cost' => $this->memory($options), + 'time_cost' => $this->time($options), + 'threads' => $this->processors($options) + ]); + } + + /** + * Set the default password threads factor. + * + * @param int $threads + * + * @return $this; + */ + public function setProcessors(int $threads) + { + $this->threads = $threads; + + return $this; + } + + /** + * Set the default password memory factor. + * + * @param int $memory + * + * @return $this + */ + public function setMemory($memory) + { + $this->memory = $memory; + + return $this; + } + + /** + * Set the default password timing factor. + * + * @param int $time + * + * @return $this + */ + public function setTime(int $time) + { + $this->time = $time; + + return $this; + } + + /** + * Extract the memory cost value from the options array. + * + * @param $options + * @return int + */ + protected function memory($options) + { + return $options['memory'] ?? $this->memory; + } + + /** + * Extract the time cost value from the options array. + * + * @param $options + * @return int + */ + protected function time($options) + { + return $options['time'] ?? $this->time; + } + + /** + * Extract the threads value from the options array. + * + * @param $options + * @return int + */ + protected function processors($options) + { + return $options['processors'] ?? $this->processors; + } +} \ No newline at end of file diff --git a/src/Illuminate/Hashing/HashManager.php b/src/Illuminate/Hashing/HashManager.php new file mode 100644 index 000000000000..f0b56c6e8d80 --- /dev/null +++ b/src/Illuminate/Hashing/HashManager.php @@ -0,0 +1,38 @@ +app['config']['hashing.driver']; + } + + /** + * Create an instance of the Brycrypt hash Driver. + * + * @return BcryptHasher + */ + public function createBcryptDriver() + { + return new BcryptHasher; + } + + /** + * Create an instance of the Argon2 hash Driver. + * + * @return ArgonHasher + */ + public function createArgonDriver() + { + return new ArgonHasher; + } +} \ No newline at end of file diff --git a/src/Illuminate/Hashing/HashServiceProvider.php b/src/Illuminate/Hashing/HashServiceProvider.php index 85581f40cf65..b4baabcb7f11 100755 --- a/src/Illuminate/Hashing/HashServiceProvider.php +++ b/src/Illuminate/Hashing/HashServiceProvider.php @@ -20,8 +20,8 @@ class HashServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton('hash', function () { - return new BcryptHasher; + $this->app->singleton('hash', function ($app) { + return (new HashManager($app))->driver(); }); } diff --git a/tests/Hashing/BcryptHasherTest.php b/tests/Hashing/BcryptHasherTest.php deleted file mode 100755 index e223b71dc4a7..000000000000 --- a/tests/Hashing/BcryptHasherTest.php +++ /dev/null @@ -1,18 +0,0 @@ -make('password'); - $this->assertNotSame('password', $value); - $this->assertTrue($hasher->check('password', $value)); - $this->assertFalse($hasher->needsRehash($value)); - $this->assertTrue($hasher->needsRehash($value, ['rounds' => 1])); - } -} diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php new file mode 100755 index 000000000000..1ac9d34089d6 --- /dev/null +++ b/tests/Hashing/HasherTest.php @@ -0,0 +1,32 @@ +make('password'); + $this->assertNotSame('password', $value); + $this->assertTrue($hasher->check('password', $value)); + $this->assertFalse($hasher->needsRehash($value)); + $this->assertTrue($hasher->needsRehash($value, ['rounds' => 1])); + } + + public function testBasicArgonHashing() + { + if (! defined('PASSWORD_ARGON2I')) { + $this->markTestSkipped('PHP not compiled with argon2 hashing support support.'); + } + + $hasher = new \Illuminate\Hashing\ArgonHasher; + $value = $hasher->make('password'); + $this->assertNotSame('password', $value); + $this->assertTrue($hasher->check('password', $value)); + $this->assertFalse($hasher->needsRehash($value)); + $this->assertTrue($hasher->needsRehash($value, ['processors' => 1])); + } +} From c946aa3098bc9435067ce8d2dc1bad5bb5ccc450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Tue, 31 Oct 2017 00:08:28 +0100 Subject: [PATCH 2/7] Fix integration tests. It was due to the new configuration not beeing loaded when integration testing took place. --- src/Illuminate/Foundation/Application.php | 2 +- tests/Integration/Auth/AuthenticationTest.php | 2 ++ tests/Integration/Http/ThrottleRequestsTest.php | 5 +++++ tests/Integration/Http/ThrottleRequestsWithRedisTest.php | 5 +++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 558df255e230..14fc68965f03 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -1111,7 +1111,7 @@ public function registerCoreContainerAliases() 'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class], 'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class], 'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class], - 'hash' => [\Illuminate\Contracts\Hashing\Hasher::class], + 'hash' => [\Illuminate\Hashing\HashManager::class], 'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class], 'log' => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class], 'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class], diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index 7faea9f38a84..475a8c5bb84e 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -24,6 +24,8 @@ protected function getEnvironmentSetUp($app) 'database' => ':memory:', 'prefix' => '', ]); + + $app['config']->set('hashing', ['driver' => 'bcrypt']); } public function setUp() diff --git a/tests/Integration/Http/ThrottleRequestsTest.php b/tests/Integration/Http/ThrottleRequestsTest.php index 824427842e34..45c5b7e9c420 100644 --- a/tests/Integration/Http/ThrottleRequestsTest.php +++ b/tests/Integration/Http/ThrottleRequestsTest.php @@ -19,6 +19,11 @@ public function tearDown() Carbon::setTestNow(null); } + public function getEnvironmentSetUp($app) + { + $app['config']->set('hashing', ['driver' => 'bcrypt']); + } + public function test_lock_opens_immediately_after_decay() { Carbon::setTestNow(null); diff --git a/tests/Integration/Http/ThrottleRequestsWithRedisTest.php b/tests/Integration/Http/ThrottleRequestsWithRedisTest.php index e4e11277110d..123e0f06a010 100644 --- a/tests/Integration/Http/ThrottleRequestsWithRedisTest.php +++ b/tests/Integration/Http/ThrottleRequestsWithRedisTest.php @@ -22,6 +22,11 @@ public function tearDown() Carbon::setTestNow(null); } + public function getEnvironmentSetUp($app) + { + $app['config']->set('hashing', ['driver' => 'bcrypt']); + } + public function test_lock_opens_immediately_after_decay() { $this->ifRedisAvailable(function () { From e4c0c56e3e43d5e533699dab70ca69f7f0f29754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Tue, 31 Oct 2017 00:39:00 +0100 Subject: [PATCH 3/7] It's argon not bcrypt. --- src/Illuminate/Hashing/ArgonHasher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 16c5ef4240ba..1d9b477f4d7c 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -45,7 +45,7 @@ public function make($value, array $options = []) ]); if ($hash === false) { - throw new RuntimeException('Bcrypt hashing not supported.'); + throw new RuntimeException('Argon2 hashing not supported.'); } return $hash; From 23c1bcfcc11aeec482438e08749b88f05e2691ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Tue, 31 Oct 2017 18:13:39 +0100 Subject: [PATCH 4/7] Added Argon helper method. And also forced both functions to be of their driver type. Also some cleanup --- src/Illuminate/Foundation/helpers.php | 22 ++++++++++++++++++++-- src/Illuminate/Hashing/ArgonHasher.php | 5 ++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index f3cbd85364df..36759e138a7f 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -124,6 +124,22 @@ function app_path($path = '') } } +if (! function_exists('argon')) { + /** + * Hash the given value against the Argon2i algorithm. + * + * @param string $value + * @param array $options + * @return string + */ + function argon($value, $options = []) + { + return app('hash') + ->driver('argon') + ->make($value, $options); + } +} + if (! function_exists('asset')) { /** * Generate an asset path for the application. @@ -185,7 +201,7 @@ function base_path($path = '') if (! function_exists('bcrypt')) { /** - * Hash the given value. + * Hash the given value against the bcrypt algorithm. * * @param string $value * @param array $options @@ -193,7 +209,9 @@ function base_path($path = '') */ function bcrypt($value, $options = []) { - return app('hash')->make($value, $options); + return app('hash') + ->driver('bcrypt') + ->make($value, $options); } } diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 1d9b477f4d7c..9e7e1ba9bd15 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -2,14 +2,13 @@ namespace Illuminate\Hashing; - use RuntimeException; use Illuminate\Contracts\Hashing\Hasher as HasherContract; class ArgonHasher implements HasherContract { /** - * Default threads factor + * Default threads factor. * * @var int */ @@ -105,7 +104,7 @@ public function setProcessors(int $threads) * * @return $this */ - public function setMemory($memory) + public function setMemory(int $memory) { $this->memory = $memory; From 7c51951a213edc83355ccd7f15a3f21a8988bed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Wed, 1 Nov 2017 08:51:09 +0100 Subject: [PATCH 5/7] Remove helper. --- src/Illuminate/Foundation/helpers.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 36759e138a7f..b5e6b3a5bc45 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -124,22 +124,6 @@ function app_path($path = '') } } -if (! function_exists('argon')) { - /** - * Hash the given value against the Argon2i algorithm. - * - * @param string $value - * @param array $options - * @return string - */ - function argon($value, $options = []) - { - return app('hash') - ->driver('argon') - ->make($value, $options); - } -} - if (! function_exists('asset')) { /** * Generate an asset path for the application. From b7ddd6c29b9b451502f7e9c2fde4a94190f8d406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Thu, 2 Nov 2017 15:19:51 +0100 Subject: [PATCH 6/7] Fix failing tests. And really forced bcrypt this time! :) --- src/Illuminate/Foundation/helpers.php | 3 +-- src/Illuminate/Hashing/HashServiceProvider.php | 12 ++++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index b5e6b3a5bc45..94742865fcf1 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -193,8 +193,7 @@ function base_path($path = '') */ function bcrypt($value, $options = []) { - return app('hash') - ->driver('bcrypt') + return app('hash.bcrypt') ->make($value, $options); } } diff --git a/src/Illuminate/Hashing/HashServiceProvider.php b/src/Illuminate/Hashing/HashServiceProvider.php index b4baabcb7f11..0357172b39c2 100755 --- a/src/Illuminate/Hashing/HashServiceProvider.php +++ b/src/Illuminate/Hashing/HashServiceProvider.php @@ -20,8 +20,16 @@ class HashServiceProvider extends ServiceProvider */ public function register() { + $this->app->singleton('hash.manager', function ($app) { + return (new HashManager($app)); + }); + $this->app->singleton('hash', function ($app) { - return (new HashManager($app))->driver(); + return $app['hash.manager']->driver(); + }); + + $this->app->singleton('hash.bcrypt', function($app) { + return $app['hash.manager']->driver('bcrypt'); }); } @@ -32,6 +40,6 @@ public function register() */ public function provides() { - return ['hash']; + return ['hash', 'hash.manager', 'hash.bcrypt']; } } From c272b15a6ed47b222c5fc1901127d12c7a51befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Lundb=C3=B8l?= Date: Sat, 4 Nov 2017 01:36:09 +0100 Subject: [PATCH 7/7] Second try on manager. --- src/Illuminate/Foundation/helpers.php | 3 ++- src/Illuminate/Hashing/HashServiceProvider.php | 12 ++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 94742865fcf1..b5e6b3a5bc45 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -193,7 +193,8 @@ function base_path($path = '') */ function bcrypt($value, $options = []) { - return app('hash.bcrypt') + return app('hash') + ->driver('bcrypt') ->make($value, $options); } } diff --git a/src/Illuminate/Hashing/HashServiceProvider.php b/src/Illuminate/Hashing/HashServiceProvider.php index 0357172b39c2..5b8d525463d9 100755 --- a/src/Illuminate/Hashing/HashServiceProvider.php +++ b/src/Illuminate/Hashing/HashServiceProvider.php @@ -20,16 +20,8 @@ class HashServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton('hash.manager', function ($app) { - return (new HashManager($app)); - }); - $this->app->singleton('hash', function ($app) { - return $app['hash.manager']->driver(); - }); - - $this->app->singleton('hash.bcrypt', function($app) { - return $app['hash.manager']->driver('bcrypt'); + return new HashManager($app); }); } @@ -40,6 +32,6 @@ public function register() */ public function provides() { - return ['hash', 'hash.manager', 'hash.bcrypt']; + return ['hash']; } }