Skip to content

Commit

Permalink
bug #34140 [Security/Core] make NativePasswordEncoder use sodium to v…
Browse files Browse the repository at this point in the history
…alidate passwords when possible (nicolas-grekas)

This PR was merged into the 4.3 branch.

Discussion
----------

[Security/Core] make NativePasswordEncoder use sodium to validate passwords when possible

| Q             | A
| ------------- | ---
| Branch?       | 4.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

sodium implementations are always faster, let's use them when possible. This also allows validating argon2 passwords when bcrypt is configured as the main one, making migrations possible.

Commits
-------

799a2ea [Security/Core] make NativePasswordEncoder use sodium to validate passwords when possible
  • Loading branch information
chalasr committed Oct 28, 2019
2 parents 591ad22 + 799a2ea commit 3be177a
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 14 deletions.
Expand Up @@ -45,7 +45,7 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
}

$this->algo = \defined('PASSWORD_ARGON2I') ? max(PASSWORD_DEFAULT, \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_ARGON2I) : PASSWORD_DEFAULT;
$this->algo = \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : (\defined('PASSWORD_ARGON2I') ? PASSWORD_ARGON2I : PASSWORD_BCRYPT);
$this->options = [
'cost' => $cost,
'time_cost' => $opsLimit,
Expand All @@ -59,32 +59,37 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos
*/
public function encodePassword($raw, $salt)
{
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || (PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) {
throw new BadCredentialsException('Invalid password.');
}

// Ignore $salt, the auto-generated one is always the best

$encoded = password_hash($raw, $this->algo, $this->options);

if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
// BCrypt encodes only the first 72 chars
throw new BadCredentialsException('Invalid password.');
}

return $encoded;
return password_hash($raw, $this->algo, $this->options);
}

/**
* {@inheritdoc}
*/
public function isPasswordValid($encoded, $raw, $salt)
{
if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
// BCrypt encodes only the first 72 chars
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
return false;
}

return \strlen($raw) <= self::MAX_PASSWORD_LENGTH && password_verify($raw, $encoded);
if (0 === strpos($encoded, '$2')) {
// BCrypt encodes only the first 72 chars
return 72 >= \strlen($raw) && password_verify($raw, $encoded);
}

if (\extension_loaded('sodium') && version_compare(\SODIUM_LIBRARY_VERSION, '1.0.14', '>=')) {
return sodium_crypto_pwhash_str_verify($encoded, $raw);
}

if (\extension_loaded('libsodium') && version_compare(phpversion('libsodium'), '1.0.14', '>=')) {
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
}

return password_verify($raw, $encoded);
}
}
Expand Up @@ -93,6 +93,6 @@ public function isPasswordValid($encoded, $raw, $salt)
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
}

throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
return false;
}
}

0 comments on commit 3be177a

Please sign in to comment.