Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
35 / 35 |
|
100.00% |
9 / 9 |
CRAP | |
100.00% |
1 / 1 |
Password | |
100.00% |
35 / 35 |
|
100.00% |
9 / 9 |
9 | |
100.00% |
1 / 1 |
hash | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
needsRehash | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
verify | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setOpsLimit | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getOpsLimit | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setMemLimit | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getMemLimit | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSodiumOpsLimit | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
getSodiumMemLimit | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 |
1 | <?php declare(strict_types=1); |
2 | /* |
3 | * This file is part of Aplus Framework Crypto Library. |
4 | * |
5 | * (c) Natan Felles <natanfelles@gmail.com> |
6 | * |
7 | * For the full copyright and license information, please view the LICENSE |
8 | * file that was distributed with this source code. |
9 | */ |
10 | namespace Framework\Crypto; |
11 | |
12 | use InvalidArgumentException; |
13 | use SensitiveParameter; |
14 | use SodiumException; |
15 | |
16 | /** |
17 | * Class Password. |
18 | * |
19 | * @package crypto |
20 | */ |
21 | class Password |
22 | { |
23 | /** |
24 | * Used to set operations or memory limit as interactive. |
25 | * It enables the use of 2 CPU operations or 64 MB RAM. |
26 | * |
27 | * @var int |
28 | */ |
29 | public const LIMIT_INTERACTIVE = 0; |
30 | /** |
31 | * Used to set operations or memory limit as moderate. |
32 | * It enables the use of 3 CPU operations or 256 MB RAM. |
33 | * |
34 | * @var int |
35 | */ |
36 | public const LIMIT_MODERATE = 1; |
37 | /** |
38 | * Used to set operations or memory limit as sensitive. |
39 | * It enables the use of 4 CPU operations or 1 GB RAM. |
40 | * |
41 | * @var int |
42 | */ |
43 | public const LIMIT_SENSITIVE = 2; |
44 | protected static int $opsLimit = Password::LIMIT_INTERACTIVE; |
45 | protected static int $memLimit = Password::LIMIT_INTERACTIVE; |
46 | |
47 | /** |
48 | * Makes a password hash. |
49 | * |
50 | * @param string $password |
51 | * @param int|null $opslimit A Password constant or null to use the default |
52 | * set for opslimit |
53 | * @param int|null $memlimit A Password constant or null to use the default |
54 | * set for memlimit. Typically, it should be paired with the opslimit value |
55 | * |
56 | * @see Password::LIMIT_INTERACTIVE |
57 | * @see Password::LIMIT_MODERATE |
58 | * @see Password::LIMIT_SENSITIVE |
59 | * |
60 | * @throws SodiumException |
61 | * |
62 | * @return string |
63 | */ |
64 | public static function hash( |
65 | #[SensitiveParameter] string $password, |
66 | int $opslimit = null, |
67 | int $memlimit = null |
68 | ) : string { |
69 | $opslimit ??= static::getOpsLimit(); |
70 | $memlimit ??= static::getMemLimit(); |
71 | return \sodium_crypto_pwhash_str( |
72 | $password, |
73 | static::getSodiumOpsLimit($opslimit), |
74 | static::getSodiumMemLimit($memlimit) |
75 | ); |
76 | } |
77 | |
78 | /** |
79 | * Checks if a hash needs to be rehashed based on the ops and mem limits. |
80 | * |
81 | * @param string $hash |
82 | * @param int|null $opslimit A Password constant or null to use the default |
83 | * set for opslimit |
84 | * @param int|null $memlimit A Password constant or null to use the default |
85 | * set for memlimit |
86 | * |
87 | * @return bool |
88 | */ |
89 | public static function needsRehash( |
90 | #[SensitiveParameter] string $hash, |
91 | int $opslimit = null, |
92 | int $memlimit = null |
93 | ) : bool { |
94 | $opslimit ??= static::getOpsLimit(); |
95 | $memlimit ??= static::getMemLimit(); |
96 | return \sodium_crypto_pwhash_str_needs_rehash( |
97 | $hash, |
98 | static::getSodiumOpsLimit($opslimit), |
99 | static::getSodiumMemLimit($memlimit) |
100 | ); |
101 | } |
102 | |
103 | /** |
104 | * Verifies a password against a hash. |
105 | * |
106 | * @param string $password |
107 | * @param string $hash |
108 | * |
109 | * @throws SodiumException |
110 | * |
111 | * @return bool |
112 | */ |
113 | public static function verify( |
114 | #[SensitiveParameter] string $password, |
115 | #[SensitiveParameter] string $hash |
116 | ) : bool { |
117 | return \sodium_crypto_pwhash_str_verify($hash, $password); |
118 | } |
119 | |
120 | /** |
121 | * Sets the default Password operations limit. |
122 | * |
123 | * @param int $opsLimit A Password constant value |
124 | * |
125 | * @see Password::LIMIT_INTERACTIVE |
126 | * @see Password::LIMIT_MODERATE |
127 | * @see Password::LIMIT_SENSITIVE |
128 | */ |
129 | public static function setOpsLimit(int $opsLimit) : void |
130 | { |
131 | static::$opsLimit = $opsLimit; |
132 | } |
133 | |
134 | /** |
135 | * Gets the default Password operations limit constant value. |
136 | * |
137 | * @return int |
138 | */ |
139 | public static function getOpsLimit() : int |
140 | { |
141 | return static::$opsLimit; |
142 | } |
143 | |
144 | /** |
145 | * Sets the default Password memory limit. |
146 | * |
147 | * @param int $memLimit A Password constant value. Typically, it should be |
148 | * paired with the opslimit value |
149 | * |
150 | * @see Password::LIMIT_INTERACTIVE |
151 | * @see Password::LIMIT_MODERATE |
152 | * @see Password::LIMIT_SENSITIVE |
153 | */ |
154 | public static function setMemLimit(int $memLimit) : void |
155 | { |
156 | static::$memLimit = $memLimit; |
157 | } |
158 | |
159 | /** |
160 | * Gets the default Password memory limit constant value. |
161 | * |
162 | * @return int |
163 | */ |
164 | public static function getMemLimit() : int |
165 | { |
166 | return static::$memLimit; |
167 | } |
168 | |
169 | /** |
170 | * Gets an appropriate sodium operations limit value from a Password constant. |
171 | * |
172 | * @param int $constant |
173 | * |
174 | * @throws InvalidArgumentException if constant value is invalid |
175 | * |
176 | * @return int |
177 | */ |
178 | protected static function getSodiumOpsLimit(int $constant) : int |
179 | { |
180 | return match ($constant) { |
181 | static::LIMIT_INTERACTIVE => \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, |
182 | static::LIMIT_MODERATE => \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE, |
183 | static::LIMIT_SENSITIVE => \SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE, |
184 | default => throw new InvalidArgumentException( |
185 | 'Invalid opslimit value: ' . $constant |
186 | ) |
187 | }; |
188 | } |
189 | |
190 | /** |
191 | * Gets an appropriate sodium memory limit value from a Password constant. |
192 | * |
193 | * @param int $constant |
194 | * |
195 | * @throws InvalidArgumentException if constant value is invalid |
196 | * |
197 | * @return int |
198 | */ |
199 | protected static function getSodiumMemLimit(int $constant) : int |
200 | { |
201 | return match ($constant) { |
202 | static::LIMIT_INTERACTIVE => \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE, |
203 | static::LIMIT_MODERATE => \SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE, |
204 | static::LIMIT_SENSITIVE => \SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE, |
205 | default => throw new InvalidArgumentException( |
206 | 'Invalid memlimit value: ' . $constant |
207 | ) |
208 | }; |
209 | } |
210 | } |