X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/password/BcryptPassword.php diff --git a/includes/password/BcryptPassword.php b/includes/password/BcryptPassword.php new file mode 100644 index 00000000..f811e3f5 --- /dev/null +++ b/includes/password/BcryptPassword.php @@ -0,0 +1,88 @@ + $this->config['cost'], + ]; + } + + protected function getDelimiter() { + return '$'; + } + + protected function parseHash( $hash ) { + parent::parseHash( $hash ); + + $this->params['rounds'] = (int)$this->params['rounds']; + } + + /** + * @param string $password Password to encrypt + * + * @throws PasswordError If bcrypt has an unknown error + * @throws MWException If bcrypt is not supported by PHP + */ + public function crypt( $password ) { + if ( !defined( 'CRYPT_BLOWFISH' ) ) { + throw new MWException( 'Bcrypt is not supported.' ); + } + + // Either use existing hash or make a new salt + // Bcrypt expects 22 characters of base64-encoded salt + // Note: bcrypt does not use MIME base64. It uses its own base64 without any '=' padding. + // It expects a 128 bit salt, so it will ignore anything after the first 128 bits + if ( !isset( $this->args[0] ) ) { + $this->args[] = substr( + // Replace + with ., because bcrypt uses a non-MIME base64 format + strtr( + // Random base64 encoded string + base64_encode( MWCryptRand::generate( 16, true ) ), + '+', '.' + ), + 0, 22 + ); + } + + $hash = crypt( $password, + sprintf( '$2y$%02d$%s', (int)$this->params['rounds'], $this->args[0] ) ); + + if ( !is_string( $hash ) || strlen( $hash ) <= 13 ) { + throw new PasswordError( 'Error when hashing password.' ); + } + + // Strip the $2y$ + $parts = explode( $this->getDelimiter(), substr( $hash, 4 ) ); + $this->params['rounds'] = (int)$parts[0]; + $this->args[0] = substr( $parts[1], 0, 22 ); + $this->hash = substr( $parts[1], 22 ); + } +}