From 6d96332b72ab635147710b3d23aca47be55c97de Mon Sep 17 00:00:00 2001 From: Ben Tadiar Date: Tue, 3 Oct 2017 22:50:08 +0100 Subject: [PATCH] Added Argon2 hash support --- .travis.yml | 6 ++ src/Illuminate/Hashing/Argon2Hasher.php | 85 +++++++++++++++++++ .../Hashing/HashServiceProvider.php | 9 +- tests/Hashing/Argon2HasherTest.php | 46 ++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Hashing/Argon2Hasher.php create mode 100644 tests/Hashing/Argon2HasherTest.php diff --git a/.travis.yml b/.travis.yml index 7d48e602f13e..42d9dbb7088b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ sudo: false cache: directories: - $HOME/.composer/cache + - $HOME/libsodium services: - memcached @@ -31,6 +32,11 @@ before_install: - phpenv config-rm xdebug.ini || true - echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - printf "\n" | pecl install -f redis + - sudo apt-get install -y software-properties-common + - sudo LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php + - sudo apt-get update + - sudo apt-get install -y libsodium-dev + - pecl install -f libsodium - travis_retry composer self-update install: diff --git a/src/Illuminate/Hashing/Argon2Hasher.php b/src/Illuminate/Hashing/Argon2Hasher.php new file mode 100644 index 000000000000..08089f496d55 --- /dev/null +++ b/src/Illuminate/Hashing/Argon2Hasher.php @@ -0,0 +1,85 @@ + $memoryCost, 'time_cost' => $timeCost]; + + // Filter unknown options from the options array + $options = array_filter($options, function ($key) use ($hashOptions) { + return isset($hashOptions[$key]); + }, ARRAY_FILTER_USE_KEY); + + return ! empty(array_diff_assoc($options, $hashOptions)); + } + + /** + * Determine if the system supports Argon2i hashing. + * + * @return bool + */ + public function isSupported(): bool + { + return extension_loaded('sodium'); + } +} diff --git a/src/Illuminate/Hashing/HashServiceProvider.php b/src/Illuminate/Hashing/HashServiceProvider.php index 85581f40cf65..10b99223d1b3 100755 --- a/src/Illuminate/Hashing/HashServiceProvider.php +++ b/src/Illuminate/Hashing/HashServiceProvider.php @@ -21,7 +21,14 @@ class HashServiceProvider extends ServiceProvider public function register() { $this->app->singleton('hash', function () { - return new BcryptHasher; + switch (config('hash.algorithm')) { + case 'argon2': + case 'argon2i': + return new Argon2Hasher; + case 'bcrypt': + default: + return new BcryptHasher; + } }); } diff --git a/tests/Hashing/Argon2HasherTest.php b/tests/Hashing/Argon2HasherTest.php new file mode 100644 index 000000000000..0e88367c3b3b --- /dev/null +++ b/tests/Hashing/Argon2HasherTest.php @@ -0,0 +1,46 @@ +isSupported()) { + $this->markTestSkipped('Argon2i hashing not supported.'); + } + } + + public function testHashPassword() + { + $hasher = new Argon2Hasher; + $hashedPassword = $hasher->make(self::PLAINTEXT_PASSWORD); + + $this->assertNotSame(self::PLAINTEXT_PASSWORD, $hashedPassword); + $this->assertStringStartsWith(SODIUM_CRYPTO_PWHASH_STRPREFIX, $hashedPassword); + } + + public function testVerifyPassword() + { + $hasher = new Argon2Hasher; + $hashedPassword = $hasher->make(self::PLAINTEXT_PASSWORD); + + $this->assertTrue($hasher->check(self::PLAINTEXT_PASSWORD, $hashedPassword)); + $this->assertFalse($hasher->check(strrev(self::PLAINTEXT_PASSWORD), $hashedPassword)); + } + + public function testNeedsRehash() + { + $hasher = new Argon2Hasher; + $hashedPassword = $hasher->make(self::PLAINTEXT_PASSWORD); + + $this->assertFalse($hasher->needsRehash($hashedPassword)); + $this->assertTrue($hasher->needsRehash($hashedPassword, ['time_cost' => 1])); + $this->assertTrue($hasher->needsRehash($hashedPassword, ['memory_cost' => 1])); + } +}