MaNGOS之验证Realm登录服务器

原文:

http://blog.sina.com.cn/s/blog_6c23c66c0100pg6j.html

 

用的是srp6算法加密的 

1.客户端先发送AUTH_LOGON_CHALLENGE消息,其中主要含有用户名,客户端版本号

2. 服务端接受到消息后,首先进行以下check

1)该ip是否被封,若封发相应错误

2)查看是否有该账户,若无发相应错误

3)查看最后一次登陆ip与账户是否绑定

若绑定 1>当前ip与last ip相同则ok 2>不同则发相应错误

若不绑定也ok

4)查看帐号是否被封,若被封发相应错误

5)获取用户名,开始SRP6计算

// multiply with 2, bytes are stored as hexstring
if(databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2)
_SetVSFields(rI); //若未在database中设s,v,则调用该方法
else
{
s.SetHexStr(databaseS.c_str()); //直接去database中的s,v
v.SetHexStr(databaseV.c_str());
}

/// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(const std::string& rI)
{
s.SetRand(s_BYTE_SIZE * 8); // s为32可字节的随机数

BigNumber I;
I.SetHexStr(rI.c_str()); //rI为 username:password的sha摘要

// In case of leading zeros in the rI hash, restore them
uint8 mDigest[SHA_DIGEST_LENGTH];
memset(mDigest, 0, SHA_DIGEST_LENGTH);
if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
memcpy(mDigest, I.AsByteArray(), I.GetNumBytes());

std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); //将username:password的sha摘要倒序

Sha1Hash sha;
sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
sha.Finalize();// 计算x = sha(s,username:password的sha摘要倒序)

BigNumber x;
x.SetBinary(sha.GetDigest(), sha.GetLength());
v = g.ModExp(x, N); // v= g^x mod N (g = 7, N 是个很长的自然数)
// No SQL injection (username escaped)
const char *v_hex, *s_hex;
v_hex = v.AsHexStr();
s_hex = s.AsHexStr();
loginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'", v_hex, s_hex, _safelogin.c_str() );
OPENSSL_free((void*)v_hex);
OPENSSL_free((void*)s_hex);
}

小结一下

在服务端计算s,v

s为32个字节的随机数

v= g^x mod N (g = 7, N 是个很长的自然数) x是s,用户名的字节序列倒置的sha哈希值

s,v存到数据库

接着计算B (服务端公钥)

B = ((v*3) + gmod) % N;

gmod = g^b mode N

b 为19个字节的随机数

向客户端发送B,g,N,s

在客户端收到B,g,N,s后

计算A 客户端公钥

A = g^a mode N

a为19为随机数


计算x

x = sha(s,I)

I = sha("username:password")

计算u

u=sha(A,B)// 公钥 (服务公钥,客户公钥)

计算S

S = (B - g^x*3)^(a+u*x)

计算K

S为32位,K为40位

是 sha(s奇部分)20位, sha(s偶部分)20位的奇偶交错组合

计算M,服务端也将有一套算法试图计算这个值,若于之相同则通过验证

t3 = sha(N)[i] ^ sha(g)[i]

t4 = sha(username)

M = sha(t3,t4,s,A,B,K)

向服务端发送A,M


服务端接受到消息后

1)检查客户端版本,不支持的版本则报错

2) SRP6验证

计算S = (A * (v^u mode N ))^b mode N

u = sha(A,B)

v= g^x mod N

x = sha(s,db中存的sha(username:password)倒序)

//对应客户端S = (B - g^x*3)^(a + u*x)

同样计算K = Interleave(S), 计算t3,t4

M = sha(t3,t4,s,A,B,K)

与客户端传来的M比较,相同则验证成功

总结

关键在于服务端,客户端各自计算S的公式个不同

虽然公钥部分服务端用A,b, 客户端用B,a 但其计算结果是相同的

x这个私钥很好地得到了隐藏

服务端传B,g,N,s

客户端传A,M

要从M获取私钥x难比登天,所以即使拦截了所有客户端服务端的会话也无法破解密码

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值