3 * Implements the AbstractPbkdf2Password class for the MediaWiki software.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 declare( strict_types
= 1 );
25 namespace MediaWiki\Password
;
28 * A PBKDF2-hashed password
30 * This is a computationally complex password hash for use in modern applications.
31 * The number of rounds can be configured by $wgPasswordConfig['pbkdf2']['cost'].
33 * To support different native implementations of PBKDF2 and the underlying
34 * hash algorithms, the following subclasses are available:
36 * - Pbkdf2PasswordUsingOpenSSL is the preferred, more efficient option
37 * and is used by default.
38 * - Pbkdf2PasswordUsingHashExtension provides compatibility with PBKDF2
39 * password hashes computed using legacy algorithms.
43 abstract class AbstractPbkdf2Password
extends ParameterizedPassword
{
44 protected function getDefaultParams(): array {
46 'algo' => $this->config
['algo'],
47 'rounds' => $this->config
['cost'],
48 'length' => $this->config
['length']
52 protected function getDelimiter(): string {
56 public function crypt( string $password ): void
{
57 if ( count( $this->args
) == 0 ) {
58 $this->args
[] = base64_encode( random_bytes( 16 ) );
61 $algo = $this->params
['algo'];
62 $salt = base64_decode( $this->args
[0] );
63 $rounds = (int)$this->params
['rounds'];
64 $length = (int)$this->params
['length'];
66 $digestAlgo = $this->getDigestAlgo( $algo );
67 if ( $digestAlgo === null ) {
68 throw new PasswordError( "Unknown or unsupported algo: $algo" );
70 if ( $rounds <= 0 ||
$rounds >= 0x7fffffff ) {
71 throw new PasswordError( 'Invalid number of rounds.' );
73 if ( $length <= 0 ||
$length >= 0x7fffffff ) {
74 throw new PasswordError( 'Invalid length.' );
77 $hash = $this->pbkdf2( $digestAlgo, $password, $salt, $rounds, $length );
78 $this->hash
= base64_encode( $hash );
82 * Get the implementation specific name for a hash algorithm.
84 * @param string $algo Algorithm specified in the password hash string
85 * @return string|null $algo Implementation specific name, or null if unsupported
87 abstract protected function getDigestAlgo( string $algo ): ?
string;
90 * Call the PBKDF2 implementation, which hashes the password.
92 * @param string $digestAlgo Implementation specific hash algorithm name
93 * @param string $password Password to hash
94 * @param string $salt Salt as a binary string
95 * @param int $rounds Number of iterations
96 * @param int $length Length of the hash value in bytes
97 * @return string Hash value as a binary string
98 * @throws PasswordError If an internal error occurs in hashing
100 abstract protected function pbkdf2(
109 /** @deprecated since 1.43 use MediaWiki\\Password\\AbstractPbkdf2Password */
110 class_alias( AbstractPbkdf2Password
::class, 'AbstractPbkdf2Password' );