/** * @param PasswordInterface $password * @param string $sealed * @param bool $validate * @param callable|null $keyProvider * @param callable|null $saltGenerator * * @return Token */ public static function fromSealed(PasswordInterface $password, string $sealed, bool $validate = true, callable $keyProvider = null, callable $saltGenerator = null) : Token { $parts = explode('*', $sealed); if (count($parts) !== 8) { throw new InvalidTokenException('Invalid token structure.'); } list($version, $pwId, $salt, $iv, $cipherText, $ttd, $macSalt, $mac) = $parts; if ($version !== Token::MAC_PREFIX . Token::MAC_FORMAT_VERSION) { throw new InvalidTokenException('Invalid token version.'); } if ($pwId !== $password->getId()) { throw new PasswordMismatchException($password->getId(), $pwId, "Token encrypted with password {$pwId}; password" . " {$password->getId()} provided for validation."); } $token = new self($password, $salt, base64_decode($iv), base64_decode($cipherText), $ttd, $keyProvider, $saltGenerator); if ($validate) { if ($token->isExpired()) { throw new ExpiredTokenException('Token expired on ' . DateTime::createFromFormat('U', $ttd)->format('c')); } $token->validateChecksum($macSalt, $mac); } return $token; }