2b9a673912
PHP registration page for AzerothCore with SRP6 salt/verifier generation, Cloudflare Turnstile + honeypot + rate limiting anti-spam, and a WoW-themed landing page with client setup instructions.
66 lines
2.3 KiB
PHP
66 lines
2.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SRP6 salt/verifier generation compatible with AzerothCore's authserver
|
|
* (same constants and algorithm as TrinityCore/MaNGOS, mandated by the WoW
|
|
* client itself, so this is stable across expansions/versions).
|
|
*
|
|
* Algorithm (matches AzerothCore's SRP6::MakeRegistrationData /
|
|
* ac-nodejs-srp6's computeVerifier):
|
|
* s = random 32 bytes (salt)
|
|
* h1 = SHA1(UPPER(username) + ":" + UPPER(password))
|
|
* x = SHA1(s . h1) interpreted as a LITTLE-endian integer
|
|
* v = g^x mod N (verifier)
|
|
* Both s and v are stored little-endian, zero-padded to 32 bytes, in the
|
|
* `account`.`salt` / `account`.`verifier` BINARY(32) columns.
|
|
*/
|
|
final class Srp6
|
|
{
|
|
// Fixed 256-bit prime and generator used by the WoW client's SRP6 implementation.
|
|
private const N_HEX = '894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7';
|
|
private const G = 7;
|
|
private const KEY_LENGTH = 32;
|
|
|
|
/**
|
|
* @return array{salt: string, verifier: string} raw 32-byte binary strings
|
|
*/
|
|
public static function makeRegistrationData(string $username, string $password): array
|
|
{
|
|
if (!extension_loaded('gmp')) {
|
|
throw new RuntimeException('Chybí PHP rozšíření GMP (php-gmp), nutné pro výpočet SRP6 verifieru.');
|
|
}
|
|
|
|
$username = strtoupper($username);
|
|
$password = strtoupper($password);
|
|
|
|
$salt = random_bytes(self::KEY_LENGTH);
|
|
|
|
$h1 = sha1($username . ':' . $password, true);
|
|
$xHash = sha1($salt . $h1, true);
|
|
|
|
$x = gmp_import($xHash, 1, GMP_LSW_FIRST | GMP_LITTLE_ENDIAN);
|
|
$n = gmp_init(self::N_HEX, 16);
|
|
$g = gmp_init(self::G, 10);
|
|
|
|
$v = gmp_powm($g, $x, $n);
|
|
|
|
$verifier = self::gmpToLittleEndianBytes($v, self::KEY_LENGTH);
|
|
|
|
return [
|
|
'salt' => $salt,
|
|
'verifier' => $verifier,
|
|
];
|
|
}
|
|
|
|
private static function gmpToLittleEndianBytes(\GMP $value, int $length): string
|
|
{
|
|
$bytes = gmp_export($value, 1, GMP_LSW_FIRST | GMP_LITTLE_ENDIAN);
|
|
if (strlen($bytes) > $length) {
|
|
throw new RuntimeException('SRP6 verifier přesáhl očekávanou délku.');
|
|
}
|
|
|
|
return str_pad($bytes, $length, "\0", STR_PAD_RIGHT);
|
|
}
|
|
}
|