最近更换了登录器,自从更新了23年核心的端再也没有搞过专门的注册端口,战神登录器真是好用,但是老战神不支持SPR6加密,新登录器倒是可以支持,但是唯一的缺点,注册时候只能留8位密钥,个人喜欢追求极致,想要注册的时候留有邮箱,似乎他留有两个网页按钮入口,何不做个嵌入式网址(也算不上嵌入,只能说可以通过战神登录器直接跳转),登录器自带的那个不要勾选了(早知道如此就不更新新的战神登录器了 ,我的DKP啊,顺便记录一下过程):
于是说干就干。由于核心是新的SPR6加密的,表里面有salt列和verifier列,所以一开始可以注册,但是无法登录,一开始走入误区了,一次次测试他的逻辑,自己傻乎乎还在挨个测试:
// 规则说明(逐个测试,从1到6):
// 1 = SRP6a SHA1 (salt + hash1) 用户名:密码 大写(最通用,旧版WOW)
// 2 = SRP6a SHA1 (hash1 + salt) 用户名:密码 大写(老的代码逻辑)
// 3 = SRP6a SHA256 (salt + hash1) 用户名:密码 大写(新版WOW)
// 4 = SRP6a SHA1 (salt + hash1) 密码:用户名 大写(反向拼接)
// 5 = SRP6a SHA1 (salt + hash1) 用户名:密码 小写(大小写差异)
// 6 = SRP6a SHA1 (salt + hash1) 用户名密码 无分隔符 大写(无分隔符)
后来朋友提醒下为啥不从SPR6.cpp去找(我居然没想到 ,突然感觉自己好傻逼),于是。。。
找到源码:azerothcore-wotlk\src\common\Cryptography\Authentication\SPRA6.cpp
- #include "SRP6.h"
- #include "CryptoRandom.h"
- #include "Util.h"
- #include <functional>
-
- using SHA1 = Acore::Crypto::SHA1;
- using SRP6 = Acore::Crypto::SRP6;
-
- /*static*/ std::array<uint8, 1> const SRP6::g = { 7 };
- /*static*/ std::array<uint8, 32> const SRP6::N = HexStrToByteArray<32>("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", true);
- /*static*/ BigNumber const SRP6::_g(SRP6::g);
- /*static*/ BigNumber const SRP6::_N(N);
-
- /*static*/ std::pair<SRP6::Salt, SRP6::Verifier> SRP6::MakeRegistrationData(std::string const& username, std::string const& password)
- {
- std::pair<SRP6::Salt, SRP6::Verifier> res;
- Crypto::GetRandomBytes(res.first); // random salt
- res.second = CalculateVerifier(username, password, res.first);
- return res;
- }
-
- /*static*/ SRP6::Verifier SRP6::CalculateVerifier(std::string const& username, std::string const& password, SRP6::Salt const& salt)
- {
- // v = g ^ H(s || H(u || ':' || p)) mod N
- return _g.ModExp(
- SHA1::GetDigestOf(
- salt,
- SHA1::GetDigestOf(username, ":", password)
- )
- ,_N).ToByteArray<32>();
- }
-
- /*static*/ SessionKey SRP6::SHA1Interleave(SRP6::EphemeralKey const& S)
- {
- // split S into two buffers
- std::array<uint8, EPHEMERAL_KEY_LENGTH / 2> buf0{}, buf1{};
- for (size_t i = 0; i < EPHEMERAL_KEY_LENGTH / 2; ++i)
- {
- buf0[i] = S[2 * i + 0];
- buf1[i] = S[2 * i + 1];
- }
-
- // find position of first nonzero byte
- size_t p = 0;
- while (p < EPHEMERAL_KEY_LENGTH && !S[p])
- ++p;
-
- if (p & 1)
- ++p; // skip one extra byte if p is odd
-
- p /= 2; // offset into buffers
-
- // hash each of the halves, starting at the first nonzero byte
- SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH / 2 - p);
- SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH / 2 - p);
-
- // stick the two hashes back together
- SessionKey K;
- for (size_t i = 0; i < SHA1::DIGEST_LENGTH; ++i)
- {
- K[2 * i + 0] = hash0[i];
- K[2 * i + 1] = hash1[i];
- }
- return K;
- }
-
- SRP6::SRP6(std::string const& username, Salt const& salt, Verifier const& verifier)
- : _I(SHA1::GetDigestOf(username)), _b(Crypto::GetRandomBytes<32>()), _v(verifier), s(salt), B(_B(_b, _v)) {}
-
- std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM)
- {
- ASSERT(!_used, "A single SRP6 object must only ever be used to verify ONCE!");
- _used = true;
-
- BigNumber const _A(A);
- if ((_A % _N).IsZero())
- return std::nullopt;
-
- BigNumber const u(SHA1::GetDigestOf(A, B));
- EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
-
- SessionKey K = SHA1Interleave(S);
-
- // NgHash = H(N) xor H(g)
- SHA1::Digest const NHash = SHA1::GetDigestOf(N);
- SHA1::Digest const gHash = SHA1::GetDigestOf(g);
- SHA1::Digest NgHash;
- std::transform(NHash.begin(), NHash.end(), gHash.begin(), NgHash.begin(), std::bit_xor<>());
-
- SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
- if (ourM == clientM)
- return K;
-
- return std::nullopt;
- }
复制代码 然后通过这个再去写,基本上就没有问题了。上效果图:
1、我把“账号管理”贴图改成了“角色解卡”,把“赞助服务”改成了“官方网站”,把“官方网站”改成了“账号管理”,美滋滋。
2、点击“账号管理”弹出如下网页:
至于登录器生成修改按钮贴图这个设置可以大家参考论坛里战神登录器教程设置,这里不展开了(按钮贴图我用PS做了,需要的可以私我)。
翠花上酸菜(回点血):
评分可见内容,需要评分 10 DKP 或以上后浏览.评分之前请先检查链接是否失效. 点此评分
|