bug #34140 [Security/Core] make NativePasswordEncoder use sodium to validate 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
-------
799a2eae2d
[Security/Core] make NativePasswordEncoder use sodium to validate passwords when possible
This commit is contained in:
commit
3be177a93f
@ -45,7 +45,7 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
|
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 = [
|
$this->options = [
|
||||||
'cost' => $cost,
|
'cost' => $cost,
|
||||||
'time_cost' => $opsLimit,
|
'time_cost' => $opsLimit,
|
||||||
@ -59,20 +59,13 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
*/
|
*/
|
||||||
public function encodePassword($raw, $salt)
|
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.');
|
throw new BadCredentialsException('Invalid password.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore $salt, the auto-generated one is always the best
|
// Ignore $salt, the auto-generated one is always the best
|
||||||
|
|
||||||
$encoded = password_hash($raw, $this->algo, $this->options);
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,11 +73,23 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
*/
|
*/
|
||||||
public function isPasswordValid($encoded, $raw, $salt)
|
public function isPasswordValid($encoded, $raw, $salt)
|
||||||
{
|
{
|
||||||
if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
|
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
|
||||||
// BCrypt encodes only the first 72 chars
|
|
||||||
return false;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,6 @@ final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSalti
|
|||||||
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user