Lines
100.00%
11 / 11
Methods
100.00%
6 / 6
Classes
100.00%
1 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| hash | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| verify | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 2 | ||
| needsRehash | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 2 | ||
| isLegacyHash | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| legacyHash | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| 27 | final class PasswordHasher | |
| 28 | { | |
| 29 | public function __construct( | |
| 30 | private readonly Configuration $configuration, | |
| 31 | ) { | |
| 32 | } | |
| 33 | ||
| 34 | /** | |
| 35 | * Hashes a password for storage using bcrypt. | |
| 36 | */ | |
| 37 | public function hash(#[SensitiveParameter] string $password): string | |
| 38 | { | |
| 39 | return password_hash($password, PASSWORD_BCRYPT); | |
| 40 | } | |
| 41 | ||
| 42 | /** | |
| 43 | * Verifies a password against a stored hash, accepting both bcrypt and | |
| 44 | * legacy salted SHA-256 hashes. | |
| 45 | */ | |
| 46 | public function verify(string $login, #[SensitiveParameter] string $password, string $storedHash): bool | |
| 47 | { | |
| 48 | if ($this->isLegacyHash($storedHash)) { | |
| 49 | return hash_equals($storedHash, $this->legacyHash($login, $password)); | |
| 50 | } | |
| 51 | ||
| 52 | return password_verify($password, $storedHash); | |
| 53 | } | |
| 54 | ||
| 55 | /** | |
| 56 | * Returns true when the stored hash should be upgraded to current bcrypt | |
| 57 | * parameters (legacy SHA-256, or bcrypt with outdated cost). | |
| 58 | */ | |
| 59 | public function needsRehash(string $storedHash): bool | |
| 60 | { | |
| 61 | if ($this->isLegacyHash($storedHash)) { | |
| 62 | return true; | |
| 63 | } | |
| 64 | ||
| 65 | return password_needs_rehash($storedHash, PASSWORD_BCRYPT); | |
| 66 | } | |
| 67 | ||
| 68 | private function isLegacyHash(string $storedHash): bool | |
| 69 | { | |
| 70 | // password_get_info() reports algo === null for non-PHC strings, | |
| 71 | // i.e. the 64-char salted SHA-256 hex hashes produced by the old scheme. | |
| 72 | return password_get_info($storedHash)['algo'] === null; | |
| 73 | } | |
| 74 | ||
| 75 | private function legacyHash(string $login, #[SensitiveParameter] string $password): string | |
| 76 | { | |
| 77 | $salt = (string) $this->configuration->get('security.salt') . $login; | |
| 78 | return hash('sha256', $password . $salt); | |
| 79 | } | |
| 80 | } |