TrinityCore SRP6验证器计算实现错误排查求助
TrinityCore SRP6验证器计算问题排查
TrinityCore已经废弃了auth表中原有的sha_pass_hash字段,改用安全性更高的SRP6方案。常规参考实现的计算结果无法匹配TrinityCore官方预期值,可对照以下问题点排查代码:
现有实现的核心错误点
- C#的
BigInteger默认要求输入字节数组为小端序,而TrinityCore SRP6逻辑中所有哈希、salt、固定参数均为大端序,现有代码的端序判断逻辑完全反向,且无需依赖系统端序判断,需统一做端序适配 BigInteger.ModPow返回的字节数组为小端序,直接返回会和TrinityCore要求存储的大端序验证器字节序完全相反,导致匹配失败- 未处理
BigInteger符号位问题:如果字节数组最高位为1,BigInteger会解析为负数,需额外补0字节避免符号错误 - 必须使用TrinityCore官方固定的N、g参数,不可自定义:N为32字节大质数
0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7,g固定为7
修正后的C#实现代码
using System.Security.Cryptography; using System.Numerics; // 预定义TrinityCore固定SRP6参数,提前转成适配BigInteger的格式 private static readonly BigInteger N = new BigInteger(new byte[] { 0xB7, 0x9B, 0x3E, 0x2A, 0x87, 0x82, 0x3C, 0xAB, 0x8F, 0x5E, 0xBF, 0xFB, 0x8E, 0xB1, 0x01, 0x08, 0x53, 0x50, 0x06, 0x29, 0x8B, 0x5B, 0xAD, 0xBD, 0x5B, 0x53, 0xE1, 0x89, 0x5E, 0x64, 0x4B, 0x89, 0x00 }); private static readonly BigInteger g = new BigInteger(new byte[] { 0x07, 0x00 }); public byte[] CalculateVerifier(string username, string password, byte[] salt) { // 第一步:计算SHA1(大写用户名:大写密码) byte[] identityBytes = Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}"); byte[] hI = SHA1.HashData(identityBytes); // 第二步:计算SHA1(salt拼接上一步的哈希值) byte[] xBytes = SHA1.HashData(salt.Concat(hI).ToArray()); // 第三步:转成BigInteger,反转字节序适配小端要求,补0避免符号错误 Array.Reverse(xBytes); byte[] xPadded = xBytes.Concat(new byte[] { 0x00 }).ToArray(); BigInteger x = new BigInteger(xPadded); // 第四步:计算g^x mod N得到验证器 BigInteger verifierBig = BigInteger.ModPow(g, x, N); // 第五步:转成大端序32字节数组,对齐TrinityCore字段要求 byte[] verifierBytes = verifierBig.ToByteArray(); if (verifierBytes.Last() == 0x00) { verifierBytes = verifierBytes.Take(verifierBytes.Length - 1).ToArray(); } Array.Reverse(verifierBytes); // 不足32字节补前导0 if (verifierBytes.Length < 32) { verifierBytes = new byte[32 - verifierBytes.Length].Concat(verifierBytes).ToArray(); } return verifierBytes; } public bool VerifySRP6Login(string username, string password, byte[] salt, byte[] storedVerifier) { byte[] calculatedVerifier = CalculateVerifier(username, password, salt); return calculatedVerifier.SequenceEqual(storedVerifier); }
PHP端对应实现参考
function calculateSRP6Verifier(string $username, string $password, string $salt): string { $N = gmp_init('894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7', 16); $g = gmp_init(7); $hI = sha1(strtoupper($username) . ':' . strtoupper($password), true); $x = sha1($salt . $hI, true); $xGmp = gmp_import($x, 1, GMP_BIG_ENDIAN); $verifierGmp = gmp_powm($g, $xGmp, $N); // 补前导0到32字节,和数据库字段对齐 return str_pad(gmp_export($verifierGmp, 1, GMP_BIG_ENDIAN), 32, "\x00", STR_PAD_LEFT); }
内容的提问来源于stack exchange,提问作者Rudi
相关产品推荐
相关产品推荐

