2 declare(strict_types = 1);
34 'isValidSalt' =>
'Using Pbkdf2PasswordHash::isValidSalt() is deprecated and will not be possible anymore in TYPO3 v10.0.',
35 'base64Encode' =>
'Using Pbkdf2PasswordHash::base64Encode() is deprecated and will not be possible anymore in TYPO3 v10.0.',
36 'base64Decode' =>
'Using Pbkdf2PasswordHash::base64Decode() is deprecated and will not be possible anymore in TYPO3 v10.0.',
42 protected const PREFIX =
'$pbkdf2-sha256$';
57 const ITOA64 =
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
90 throw new \InvalidArgumentException(
91 'hash_count must not be lower than 1000 or bigger than 10000000',
95 $newOptions[
'hash_count'] = (int)
$options[
'hash_count'];
97 $this->options = $newOptions;
108 public function checkPassword(
string $plainPW,
string $saltedHashPW):
bool
120 return function_exists(
'hash_pbkdf2');
132 if ($salt !==
null) {
133 trigger_error(static::class .
': using a custom salt is deprecated.', E_USER_DEPRECATED);
146 $isValid = !strncmp(self::PREFIX, $saltedPW, strlen(self::PREFIX));
166 if (strncmp($saltedPW, self::PREFIX, strlen(self::PREFIX)) || !$this->
isValidSalt($saltedPW)) {
171 return $iterationCount !==
null && $iterationCount < $this->options[
'hash_count'];
182 $iterationCount =
null;
183 $setting = substr($setting, strlen(self::PREFIX));
184 $firstSplitPos = strpos($setting,
'$');
186 if ($firstSplitPos !==
false
187 && $firstSplitPos <= strlen((
string)10000000)
188 && is_numeric(substr($setting, 0, $firstSplitPos))
190 $iterationCount = (int)substr($setting, 0, $firstSplitPos);
192 return $iterationCount;
205 if ($password !==
'') {
206 $hashCount = $this->options[
'hash_count'];
213 $hash = hash_pbkdf2(
'sha256', $password, $salt, $hashCount, 0,
true);
214 $saltWithSettings = $salt;
216 if (strlen($salt) === 16) {
217 $saltWithSettings = self::PREFIX . sprintf(
'%02u', $hashCount) .
'$' . $this->
base64Encode($salt, 16);
219 $saltedPW = $saltWithSettings .
'$' . $this->
base64Encode($hash, strlen($hash));
237 return GeneralUtility::makeInstance(Random::class)->generateRandomBytes(16);
249 if (!strncmp(
'$', $salt, 1)) {
250 if (!strncmp(self::PREFIX, $salt, strlen(self::PREFIX))) {
251 $saltParts = GeneralUtility::trimExplode(
'$', $salt, 4);
252 $salt = $saltParts[2];
265 return './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
276 $isValid = ($skip =
false);
278 if (strlen($salt) >= $reqLenBase64) {
280 if (!strncmp(
'$', $salt, 1)) {
281 if (!strncmp(self::PREFIX, $salt, strlen(self::PREFIX))) {
283 $salt = substr($salt, strrpos($salt,
'$') + 1);
289 if (!$skip && strlen($salt) >= $reqLenBase64) {
290 if (preg_match(
'/^[' . preg_quote($this->
getItoa64(),
'/') .
']{' . $reqLenBase64 .
',' . $reqLenBase64 .
'}$/', substr($salt, 0, $reqLenBase64))) {
308 return (
int)ceil($byteLength * 8 / 6);
319 protected function base64Encode(
string $input,
int $count):
string
321 $input = substr($input, 0, $count);
322 return rtrim(str_replace(
'+',
'.', base64_encode($input)),
" =\r\n\t\0\x0B");
334 return base64_decode(str_replace(
'.',
'+', $value));
345 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
346 return $this->options[
'hash_count'];
357 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
369 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
381 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
393 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
405 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
406 if ($hashCount >= 1000 && $hashCount <= 10000000) {
407 $this->options[
'hash_count'] = $hashCount;
419 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
431 trigger_error(
'This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);