Files
moonwell-web/app/Services/VMangosSrpService.php
2026-10-03 14:33:08 +04:00

71 lines
2.4 KiB
PHP

<?php
namespace App\Services;
use Brick\Math\BigInteger;
class VMangosSrpService
{
private const string MODULUS_HEX = '894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7';
private const int GENERATOR = 7;
private const int BYTE_LENGTH = 32;
public function normalizeUsername(string $username): string
{
return strtoupper(trim($username));
}
public function normalizeEmail(string $email): string
{
return strtoupper(trim($email));
}
public function normalizePassword(string $password): string
{
return strtoupper($password);
}
/**
* @return array{0: string, 1: string}
*/
public function makeRegistrationData(string $username, string $password): array
{
$salt = random_bytes(self::BYTE_LENGTH);
$salt[0] = chr(ord($salt[0]) | 0x80);
$saltHex = strtoupper(bin2hex($salt));
return [$saltHex, $this->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'),
);
}
}