makeVerifierHex($username, $password, $saltHex)]; } public function makeVerifierHex(string $username, string $password, string $saltHex): string { $normalizedUsername = $this->normalizeUsername($username); $normalizedPassword = $this->normalizePassword($password); $salt = hex2bin($saltHex); if ($salt === false) { throw new \InvalidArgumentException('Invalid salt hex provided.'); } $innerDigest = hash('sha1', sprintf('%s:%s', $normalizedUsername, $normalizedPassword), true); $xDigest = hash('sha1', $salt.$innerDigest, true); $modulus = BigInteger::fromBase(self::MODULUS_HEX, 16); $exponent = BigInteger::fromBytes(strrev($xDigest), false); $verifier = BigInteger::of(self::GENERATOR)->modPow($exponent, $modulus); $verifierBytes = strrev(str_pad($verifier->toBytes(false), self::BYTE_LENGTH, "\0", STR_PAD_LEFT)); return strtoupper(bin2hex($verifierBytes)); } public function credentialsMatch(string $username, string $password, string $saltHex, string $verifierHex): bool { return hash_equals( strtoupper($verifierHex), $this->makeVerifierHex($username, $password, $saltHex), ); } }