makeVerifierHex($username, $password, $saltHex)]; } public function makeVerifierHex(string $username, string $password, string $saltHex): string { $normalizedUsername = $this->normalizeUsername($username); $normalizedPassword = $this->normalizePassword($password); // vMaNGOS stores BigNumber::AsHexStr() (big endian) and hashes // BigNumber::AsByteArray() (little endian). $normalizedSalt = ltrim($saltHex, '0'); $salt = hex2bin(str_pad($normalizedSalt, (int) (ceil(strlen($normalizedSalt) / 2) * 2), '0', STR_PAD_LEFT)); if ($salt === false || $salt === '') { throw new \InvalidArgumentException('Invalid salt hex provided.'); } $innerDigest = hash('sha1', sprintf('%s:%s', $normalizedUsername, $normalizedPassword), true); $xDigest = hash('sha1', strrev($salt).$innerDigest, true); $modulus = BigInteger::fromBase(self::MODULUS_HEX, 16); $exponent = BigInteger::fromBytes(strrev($xDigest), false); $verifier = BigInteger::of(self::GENERATOR)->modPow($exponent, $modulus); return strtoupper($verifier->toBase(16)); } public function credentialsMatch(string $username, string $password, string $saltHex, string $verifierHex): bool { return hash_equals( ltrim(strtoupper($verifierHex), '0'), ltrim($this->makeVerifierHex($username, $password, $saltHex), '0'), ); } }