Commit 5bb7e76e authored by Christian Futterlieb's avatar Christian Futterlieb Committed by Benni Mack
Browse files

[!!!][TASK] Implement Salted Passwords against SaltInterface

Salt classes must implement SaltInterface only. The AbstractSalt
class is renamed to AbstractComposedSalt and implements
SaltInterface. Methods for salt-classes that compose the
password-hash string themselves (which are currently all in
saltedpasswords) are moved to AbstractComposedSalt as well.

This cleanup change prepares for the integration of the
PHP password API in a following change.

Relates: #79795
Relates: #79889
Resolves: #83294
Releases: master
Change-Id: Ife24aa39be99c5ad391b0f10497a2bceb04084f3
Reviewed-on: https://review.typo3.org/52737


Reviewed-by: default avatarStefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 940051e6
......@@ -84,6 +84,7 @@
"typo3/sysext/info/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/lowlevel/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/reports/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/saltedpasswords/Migrations/Code/ClassAliasMap.php",
"typo3/sysext/workspaces/Migrations/Code/ClassAliasMap.php"
]
},
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "6b0c9ff22949275bc4d6c60fd2f62f2b",
"content-hash": "ee8fd70e59c3f86ff7728b866e54149c",
"packages": [
{
"name": "cogpowered/finediff",
......
.. include:: ../../Includes.txt
===============================================================================
Breaking: #83294 - Salted Passwords: Custom saltings must use the SaltInterface
===============================================================================
See :issue:`83294`
Description
===========
The salted passwords factory allowed to register custom saltings has been changed. All custom salts
need to implement :php:`TYPO3\CMS\SaltedPasswords\Salt\SaltInterface`. Before, this was
handled by extending from :php:`TYPO3\CMS\SaltedPasswords\Salt\AbstractSalt`, which has been renamed to
:php:`TYPO3\CMS\SaltedPasswords\Salt\AbstractComposedSalt` when the salting is implemented.
Impact
======
When writing custom salts for TYPO3, they need to implement the SaltInterface.
If extending from :php:`AbstractSalt`, custom salt now need to extend from :php:`AbstractComposedSalt` and
implement the additional method :php:`getSaltLength()` and :php:`isValidSalt($salt)`.
Affected Installations
======================
TYPO3 installations using custom salts for `EXT:saltedpasswords`.
Migration
=========
Switch to the new implemention details mentioned above, and change your custom salt to fit
to the :php:`SaltInterface` API.
.. index:: PHP-API, NotScanned
\ No newline at end of file
......@@ -14,6 +14,9 @@ namespace TYPO3\CMS\Saltedpasswords\Evaluation;
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Saltedpasswords\Salt\SaltFactory;
use TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility;
/**
* Class implementing salted evaluation methods.
*/
......@@ -49,20 +52,19 @@ class Evaluator
*/
public function evaluateFieldValue($value, $is_in, &$set)
{
$isEnabled = $this->mode ? \TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled($this->mode) : \TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled();
$isEnabled = $this->mode ? SaltedPasswordsUtility::isUsageEnabled($this->mode) : SaltedPasswordsUtility::isUsageEnabled();
if ($isEnabled) {
$isMD5 = preg_match('/[0-9abcdef]{32,32}/', $value);
$hashingMethod = substr($value, 0, 2);
$isDeprecatedSaltedHash = ($hashingMethod === 'C$' || $hashingMethod === 'M$');
/** @var $objInstanceSaltedPW \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface */
$objInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null, $this->mode);
$objInstanceSaltedPW = SaltFactory::getSaltingInstance(null, $this->mode);
if ($isMD5) {
$set = true;
$value = 'M' . $objInstanceSaltedPW->getHashedPassword($value);
} else {
// Determine method used for the (possibly) salted hashed password
$tempValue = $isDeprecatedSaltedHash ? substr($value, 1) : $value;
$tempObjInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($tempValue);
$tempObjInstanceSaltedPW = SaltFactory::getSaltingInstance($tempValue);
if (!is_object($tempObjInstanceSaltedPW)) {
$set = true;
$value = $objInstanceSaltedPW->getHashedPassword($value);
......
<?php
declare(strict_types=1);
namespace TYPO3\CMS\Saltedpasswords\Salt;
/*
......@@ -16,9 +17,9 @@ namespace TYPO3\CMS\Saltedpasswords\Salt;
/**
* Abstract class with methods needed to be extended
* in a salted hashing class.
* in a salted hashing class that composes an own salted password hash.
*/
abstract class AbstractSalt
abstract class AbstractComposedSalt implements SaltInterface
{
/**
* Method applies settings (prefix, optional hash count, optional suffix)
......@@ -27,28 +28,43 @@ abstract class AbstractSalt
* @param string $salt A salt to apply setting to
* @return string Salt with setting
*/
abstract protected function applySettingsToSalt($salt);
abstract protected function applySettingsToSalt(string $salt): string;
/**
* Generates a random base salt settings for the hash.
*
* @return string A string containing settings and a random salt
*/
abstract protected function getGeneratedSalt();
abstract protected function getGeneratedSalt(): string;
/**
* Returns a string for mapping an int to the corresponding base 64 character.
*
* @return string String for mapping an int to the corresponding base 64 character
*/
abstract protected function getItoa64();
abstract protected function getItoa64(): string;
/**
* Returns setting string to indicate type of hashing method.
*
* @return string Setting string of hashing method
*/
abstract protected function getSetting();
abstract protected function getSetting(): string;
/**
* Returns length of required salt.
*
* @return int Length of required salt
*/
abstract public function getSaltLength(): int;
/**
* Method determines if a given string is a valid salt
*
* @param string $salt String to check
* @return bool TRUE if it's valid salt, otherwise FALSE
*/
abstract public function isValidSalt(string $salt): bool;
/**
* Encodes bytes into printable base 64 using the *nix standard from crypt().
......@@ -57,7 +73,7 @@ abstract class AbstractSalt
* @param int $count The number of characters (bytes) to encode.
* @return string Encoded string
*/
public function base64Encode($input, $count)
public function base64Encode(string $input, int $count): string
{
$output = '';
$i = 0;
......@@ -91,7 +107,7 @@ abstract class AbstractSalt
* @param int $byteLength Length of bytes to calculate in base64 chars
* @return int Required length of base64 characters
*/
protected function getLengthBase64FromBytes($byteLength)
protected function getLengthBase64FromBytes(int $byteLength): int
{
// Calculates bytes in bits in base64
return (int)ceil($byteLength * 8 / 6);
......
<?php
declare(strict_types=1);
namespace TYPO3\CMS\Saltedpasswords\Salt;
/*
......@@ -87,7 +88,7 @@ class BlowfishSalt extends Md5Salt
* @param string $salt A salt to apply setting to
* @return string Salt with setting
*/
protected function applySettingsToSalt($salt)
protected function applySettingsToSalt(string $salt): string
{
$saltWithSettings = $salt;
$reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
......@@ -104,7 +105,7 @@ class BlowfishSalt extends Md5Salt
* @param string $setting Complete hash or a hash's setting string or to get log2 iteration count from
* @return int Used hashcount for given hash string
*/
protected function getCountLog2($setting)
protected function getCountLog2(string $setting): int
{
$countLog2 = null;
$setting = substr($setting, strlen($this->getSetting()));
......@@ -124,7 +125,7 @@ class BlowfishSalt extends Md5Salt
* @see $hashCount
* @see setHashCount()
*/
public function getHashCount()
public function getHashCount(): int
{
return isset(self::$hashCount) ? self::$hashCount : self::HASH_COUNT;
}
......@@ -137,7 +138,7 @@ class BlowfishSalt extends Md5Salt
* @see $maxHashCount
* @see setMaxHashCount()
*/
public function getMaxHashCount()
public function getMaxHashCount(): int
{
return isset(self::$maxHashCount) ? self::$maxHashCount : self::MAX_HASH_COUNT;
}
......@@ -147,9 +148,9 @@ class BlowfishSalt extends Md5Salt
*
* @return bool Method available
*/
public function isAvailable()
public function isAvailable(): bool
{
return CRYPT_BLOWFISH;
return (bool)CRYPT_BLOWFISH;
}
/**
......@@ -160,7 +161,7 @@ class BlowfishSalt extends Md5Salt
* @see $minHashCount
* @see setMinHashCount()
*/
public function getMinHashCount()
public function getMinHashCount(): int
{
return isset(self::$minHashCount) ? self::$minHashCount : self::MIN_HASH_COUNT;
}
......@@ -173,7 +174,7 @@ class BlowfishSalt extends Md5Salt
*
* @return int Length of a Blowfish salt in bytes
*/
public function getSaltLength()
public function getSaltLength(): int
{
return self::$saltLengthBlowfish;
}
......@@ -186,7 +187,7 @@ class BlowfishSalt extends Md5Salt
*
* @return string Setting string of Blowfish salted hashes
*/
public function getSetting()
public function getSetting(): string
{
return self::$settingBlowfish;
}
......@@ -202,7 +203,7 @@ class BlowfishSalt extends Md5Salt
* @param string $saltedPW Salted hash to check if it needs an update
* @return bool TRUE if salted hash needs an update, otherwise FALSE
*/
public function isHashUpdateNeeded($saltedPW)
public function isHashUpdateNeeded(string $saltedPW): bool
{
// Check whether this was an updated password.
if (strncmp($saltedPW, '$2', 2) || !$this->isValidSalt($saltedPW)) {
......@@ -222,7 +223,7 @@ class BlowfishSalt extends Md5Salt
* @param string $salt String to check
* @return bool TRUE if it's valid salt, otherwise FALSE
*/
public function isValidSalt($salt)
public function isValidSalt(string $salt): bool
{
$isValid = ($skip = false);
$reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
......@@ -252,7 +253,7 @@ class BlowfishSalt extends Md5Salt
* @param string $saltedPW String to check
* @return bool TRUE if it's valid salted hashed password, otherwise FALSE
*/
public function isValidSaltedPW($saltedPW)
public function isValidSaltedPW(string $saltedPW): bool
{
$isValid = !strncmp($this->getSetting(), $saltedPW, strlen($this->getSetting()));
if ($isValid) {
......@@ -269,9 +270,9 @@ class BlowfishSalt extends Md5Salt
* @see $hashCount
* @see getHashCount()
*/
public function setHashCount($hashCount = null)
public function setHashCount(int $hashCount = null)
{
self::$hashCount = !is_null($hashCount) && is_int($hashCount) && $hashCount >= $this->getMinHashCount() && $hashCount <= $this->getMaxHashCount() ? $hashCount : self::HASH_COUNT;
self::$hashCount = !is_null($hashCount) && $hashCount >= $this->getMinHashCount() && $hashCount <= $this->getMaxHashCount() ? $hashCount : self::HASH_COUNT;
}
/**
......@@ -282,9 +283,9 @@ class BlowfishSalt extends Md5Salt
* @see $maxHashCount
* @see getMaxHashCount()
*/
public function setMaxHashCount($maxHashCount = null)
public function setMaxHashCount(int $maxHashCount = null)
{
self::$maxHashCount = !is_null($maxHashCount) && is_int($maxHashCount) ? $maxHashCount : self::MAX_HASH_COUNT;
self::$maxHashCount = $maxHashCount ?? self::MAX_HASH_COUNT;
}
/**
......@@ -295,8 +296,8 @@ class BlowfishSalt extends Md5Salt
* @see $minHashCount
* @see getMinHashCount()
*/
public function setMinHashCount($minHashCount = null)
public function setMinHashCount(int $minHashCount = null)
{
self::$minHashCount = !is_null($minHashCount) && is_int($minHashCount) ? $minHashCount : self::MIN_HASH_COUNT;
self::$minHashCount = $minHashCount ?? self::MIN_HASH_COUNT;
}
}
<?php
declare(strict_types=1);
namespace TYPO3\CMS\Saltedpasswords\Salt;
/*
......@@ -24,7 +25,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
* MD5 salted hashing with PHP's crypt() should be available
* on most of the systems.
*/
class Md5Salt extends AbstractSalt implements SaltInterface
class Md5Salt extends AbstractComposedSalt
{
/**
* Keeps a string for mapping an int to the corresponding
......@@ -59,7 +60,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $salt A salt to apply setting to
* @return string Salt with setting
*/
protected function applySettingsToSalt($salt)
protected function applySettingsToSalt(string $salt): string
{
$saltWithSettings = $salt;
$reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
......@@ -78,7 +79,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $saltedHashPW salted hash to compare plain-text password with
* @return bool TRUE, if plain-text password matches the salted hash, otherwise FALSE
*/
public function checkPassword($plainPW, $saltedHashPW)
public function checkPassword(string $plainPW, string $saltedHashPW): bool
{
$isCorrect = false;
if ($this->isValidSalt($saltedHashPW)) {
......@@ -98,7 +99,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return string A character string containing settings and a random salt
*/
protected function getGeneratedSalt()
protected function getGeneratedSalt(): string
{
$randomBytes = GeneralUtility::makeInstance(Random::class)->generateRandomBytes($this->getSaltLength());
return $this->base64Encode($randomBytes, $this->getSaltLength());
......@@ -111,7 +112,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $salt Optional custom salt with setting to use
* @return string Salted hashed password
*/
public function getHashedPassword($password, $salt = null)
public function getHashedPassword(string $password, string $salt = null)
{
$saltedPW = null;
if (!empty($password)) {
......@@ -128,7 +129,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return string String for mapping an int to the corresponding base 64 character
*/
protected function getItoa64()
protected function getItoa64(): string
{
return self::ITOA64;
}
......@@ -138,9 +139,9 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return bool Method available
*/
public function isAvailable()
public function isAvailable(): bool
{
return CRYPT_MD5;
return (bool)CRYPT_MD5;
}
/**
......@@ -148,7 +149,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return int Length of a MD5 salt in bytes
*/
public function getSaltLength()
public function getSaltLength(): int
{
return self::$saltLengthMD5;
}
......@@ -158,7 +159,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return string Suffix of a salt
*/
protected function getSaltSuffix()
protected function getSaltSuffix(): string
{
return self::$saltSuffixMD5;
}
......@@ -168,7 +169,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
*
* @return string Setting string of MD5 salted hashes
*/
public function getSetting()
public function getSetting(): string
{
return self::$settingMD5;
}
......@@ -185,7 +186,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $passString Salted hash to check if it needs an update
* @return bool TRUE if salted hash needs an update, otherwise FALSE
*/
public function isHashUpdateNeeded($passString)
public function isHashUpdateNeeded(string $passString): bool
{
return false;
}
......@@ -196,7 +197,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $salt String to check
* @return bool TRUE if it's valid salt, otherwise FALSE
*/
public function isValidSalt($salt)
public function isValidSalt(string $salt): bool
{
$isValid = ($skip = false);
$reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
......@@ -226,7 +227,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface
* @param string $saltedPW String to check
* @return bool TRUE if it's valid salted hashed password, otherwise FALSE
*/
public function isValidSaltedPW($saltedPW)
public function isValidSaltedPW(string $saltedPW): bool
{
$isValid = !strncmp($this->getSetting(), $saltedPW, strlen($this->getSetting()));
if ($isValid) {
......
<?php
declare(strict_types=1);
namespace TYPO3\CMS\Saltedpasswords\Salt;
/*
......@@ -21,7 +22,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
* Class that implements PBKDF2 salted hashing based on PHP's
* hash_pbkdf2() function.
*/
class Pbkdf2Salt extends AbstractSalt implements SaltInterface
class Pbkdf2Salt extends AbstractComposedSalt
{
/**
* Keeps a string for mapping an int to the corresponding
......@@ -88,7 +89,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $salt A salt to apply setting to
* @return string Salt with setting
*/
protected function applySettingsToSalt($salt)
protected function applySettingsToSalt(string $salt): string
{
$saltWithSettings = $salt;
// salt without setting
......@@ -106,7 +107,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $saltedHashPW salted hash to compare plain-text password with
* @return bool TRUE, if plain-text password matches the salted hash, otherwise FALSE
*/
public function checkPassword($plainPW, $saltedHashPW)
public function checkPassword(string $plainPW, string $saltedHashPW): bool
{
return $this->isValidSalt($saltedHashPW) && \hash_equals($this->getHashedPassword($plainPW, $saltedHashPW), $saltedHashPW);
}
......@@ -117,7 +118,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $setting Complete hash or a hash's setting string or to get log2 iteration count from
* @return int|null Used hashcount for given hash string
*/
protected function getIterationCount($setting)
protected function getIterationCount(string $setting)
{
$iterationCount = null;
$setting = substr($setting, strlen($this->getSetting()));
......@@ -143,7 +144,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
*
* @return string A character string containing settings and a random salt
*/
protected function getGeneratedSalt()
protected function getGeneratedSalt(): string
{
return GeneralUtility::makeInstance(Random::class)->generateRandomBytes($this->getSaltLength());
}
......@@ -155,7 +156,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $salt
* @return string
*/
protected function getStoredSalt($salt)
protected function getStoredSalt(string $salt): string
{
if (!strncmp('$', $salt, 1)) {
if (!strncmp($this->getSetting(), $salt, strlen($this->getSetting()))) {
......@@ -171,7 +172,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
*
* @return string String for mapping an int to the corresponding base 64 character
*/
protected function getItoa64()
protected function getItoa64(): string
{
return self::ITOA64;
}
......@@ -183,7 +184,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $salt Optional custom salt with setting to use
* @return string|null Salted hashed password
*/
public function getHashedPassword($password, $salt = null)
public function getHashedPassword(string $password, string $salt = null)
{
$saltedPW = null;
if ($password !== '') {
......@@ -207,7 +208,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @see $hashCount
* @see setHashCount()
*/
public function getHashCount()
public function getHashCount(): int
{
return isset(self::$hashCount) ? self::$hashCount : self::HASH_COUNT;
}
......@@ -220,7 +221,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @see $maxHashCount
* @see setMaxHashCount()
*/
public function getMaxHashCount()
public function getMaxHashCount(): int
{
return isset(self::$maxHashCount) ? self::$maxHashCount : self::MAX_HASH_COUNT;
}
......@@ -230,7 +231,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
*
* @return bool Method available
*/
public function isAvailable()
public function isAvailable(): bool
{
return function_exists('hash_pbkdf2');
}
......@@ -243,7 +244,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @see $minHashCount
* @see setMinHashCount()
*/
public function getMinHashCount()
public function getMinHashCount(): int
{
return isset(self::$minHashCount) ? self::$minHashCount : self::MIN_HASH_COUNT;
}
......@@ -256,7 +257,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
*
* @return int Length of a PBKDF2 salt in bytes
*/
public function getSaltLength()
public function getSaltLength(): int
{
return self::$saltLengthPbkdf2;
}
......@@ -269,7 +270,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
*
* @return string Setting string of PBKDF2 salted hashes
*/
public function getSetting()
public function getSetting(): string
{
return self::$settingPbkdf2;
}
......@@ -285,7 +286,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $saltedPW Salted hash to check if it needs an update
* @return bool TRUE if salted hash needs an update, otherwise FALSE
*/
public function isHashUpdateNeeded($saltedPW)
public function isHashUpdateNeeded(string $saltedPW): bool
{
// Check whether this was an updated password.
if (strncmp($saltedPW, $this->getSetting(), strlen($this->getSetting())) || !$this->isValidSalt($saltedPW)) {
......@@ -305,7 +306,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $salt String to check
* @return bool TRUE if it's valid salt, otherwise FALSE
*/
public function isValidSalt($salt)
public function isValidSalt(string $salt): bool
{
$isValid = ($skip = false);
$reqLenBase64 = $this->getLengthBase64FromBytes($this->getSaltLength());
......@@ -335,7 +336,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @param string $saltedPW String to check
* @return bool TRUE if it's valid salted hashed password, otherwise FALSE
*/
public function isValidSaltedPW($saltedPW)
public function isValidSaltedPW(string $saltedPW): bool
{
$isValid = !strncmp($this->getSetting(), $saltedPW, strlen($this->getSetting()));
if ($isValid) {
......@@ -352,9 +353,9 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @see $hashCount
* @see getHashCount()
*/
public function setHashCount($hashCount = null)
public function setHashCount(int $hashCount = null)
{
self::$hashCount = !is_null($hashCount) && is_int($hashCount) && $hashCount >= $this->getMinHashCount() && $hashCount <= $this->getMaxHashCount() ? $hashCount : self::HASH_COUNT;
self::$hashCount = !is_null($hashCount) && $hashCount >= $this->getMinHashCount() && $hashCount <= $this->getMaxHashCount() ? $hashCount : self::HASH_COUNT;
}
/**
......@@ -365,9 +366,9 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface
* @see $maxHashCount
* @see getMaxHashCount()
*/
public function setMaxHashCount($maxHashCount = null)