config['types'] as $type ) { $passObj = $this->factory->newFromType( $type ); if ( !$passObj instanceof ParameterizedPassword ) { throw new MWException( 'Underlying type must be a parameterized password.' ); } elseif ( $passObj->getDelimiter() === $this->getDelimiter() ) { throw new MWException( 'Underlying type cannot use same delimiter as encapsulating type.' ); } $params[] = implode( $passObj->getDelimiter(), $passObj->getDefaultParams() ); } return $params; } public function crypt( $password ) { $lastHash = $password; foreach ( $this->config['types'] as $i => $type ) { // Construct pseudo-hash based on params and arguments /** @var ParameterizedPassword $passObj */ $passObj = $this->factory->newFromType( $type ); $params = ''; $args = ''; if ( $this->params[$i] !== '' ) { $params = $this->params[$i] . $passObj->getDelimiter(); } if ( isset( $this->args[$i] ) && $this->args[$i] !== '' ) { $args = $this->args[$i] . $passObj->getDelimiter(); } $existingHash = ":$type:" . $params . $args . $this->hash; // Hash the last hash with the next type in the layer $passObj = $this->factory->newFromCiphertext( $existingHash ); $passObj->crypt( $lastHash ); // Move over the params and args $this->params[$i] = implode( $passObj->getDelimiter(), $passObj->params ); $this->args[$i] = implode( $passObj->getDelimiter(), $passObj->args ); $lastHash = $passObj->hash; } $this->hash = $lastHash; } /** * Finish the hashing of a partially hashed layered hash * * Given a password hash that is hashed using the first layer of this object's * configuration, perform the remaining layers of password hashing in order to * get an updated hash with all the layers. * * @param ParameterizedPassword $passObj Password hash of the first layer * * @throws MWException If the first parameter is not of the correct type */ public function partialCrypt( ParameterizedPassword $passObj ) { $type = $passObj->config['type']; if ( $type !== $this->config['types'][0] ) { throw new MWException( 'Only a hash in the first layer can be finished.' ); } // Gather info from the existing hash $this->params[0] = implode( $passObj->getDelimiter(), $passObj->params ); $this->args[0] = implode( $passObj->getDelimiter(), $passObj->args ); $lastHash = $passObj->hash; // Layer the remaining types foreach ( $this->config['types'] as $i => $type ) { if ( $i == 0 ) { continue; } // Construct pseudo-hash based on params and arguments /** @var ParameterizedPassword $passObj */ $passObj = $this->factory->newFromType( $type ); $params = ''; $args = ''; if ( $this->params[$i] !== '' ) { $params = $this->params[$i] . $passObj->getDelimiter(); } if ( isset( $this->args[$i] ) && $this->args[$i] !== '' ) { $args = $this->args[$i] . $passObj->getDelimiter(); } $existingHash = ":$type:" . $params . $args . $this->hash; // Hash the last hash with the next type in the layer $passObj = $this->factory->newFromCiphertext( $existingHash ); $passObj->crypt( $lastHash ); // Move over the params and args $this->params[$i] = implode( $passObj->getDelimiter(), $passObj->params ); $this->args[$i] = implode( $passObj->getDelimiter(), $passObj->args ); $lastHash = $passObj->hash; } $this->hash = $lastHash; } }