RealmSession.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Threading.Tasks;
  4. using BossBase;
  5. using Helper;
  6. using Logger;
  7. namespace BossClient
  8. {
  9. public class RealmSession: IDisposable
  10. {
  11. public int ID { get; set; }
  12. public IMessageChannel MessageChannel { get; set; }
  13. public RealmSession(int id, IMessageChannel messageChannel)
  14. {
  15. this.ID = id;
  16. this.MessageChannel = messageChannel;
  17. }
  18. public void Dispose()
  19. {
  20. this.MessageChannel.Dispose();
  21. }
  22. public async Task<SMSG_Password_Protect_Type> Handle_SMSG_Password_Protect_Type()
  23. {
  24. var result = await this.MessageChannel.RecvMessage();
  25. ushort opcode = result.Item1;
  26. byte[] message = result.Item2;
  27. if (opcode != MessageOpcode.SMSG_PASSWORD_PROTECT_TYPE)
  28. {
  29. throw new BossException(string.Format("session: {0}, opcode: {1}", this.ID, opcode));
  30. }
  31. var smsgPasswordProtectType =
  32. ProtobufHelper.FromBytes<SMSG_Password_Protect_Type>(message);
  33. return smsgPasswordProtectType;
  34. }
  35. public async Task<SMSG_Auth_Logon_Challenge_Response>
  36. Handle_SMSG_Auth_Logon_Challenge_Response()
  37. {
  38. var result = await this.MessageChannel.RecvMessage();
  39. ushort opcode = result.Item1;
  40. byte[] message = result.Item2;
  41. if (opcode != MessageOpcode.SMSG_AUTH_LOGON_CHALLENGE_RESPONSE)
  42. {
  43. Log.Trace("opcode: {0}", opcode);
  44. throw new BossException(string.Format("session: {0}, opcode: {1}", this.ID, opcode));
  45. }
  46. var smsgAuthLogonChallengeResponse =
  47. ProtobufHelper.FromBytes<SMSG_Auth_Logon_Challenge_Response>(message);
  48. return smsgAuthLogonChallengeResponse;
  49. }
  50. public async Task<SMSG_Auth_Logon_Proof_M2> Handle_SMSG_Auth_Logon_Proof_M2()
  51. {
  52. var result = await this.MessageChannel.RecvMessage();
  53. ushort opcode = result.Item1;
  54. byte[] message = result.Item2;
  55. if (opcode != MessageOpcode.SMSG_AUTH_LOGON_PROOF_M2)
  56. {
  57. throw new BossException(string.Format("session: {0}, error opcode: {1}", this.ID,
  58. opcode));
  59. }
  60. var smsgAuthLogonProofM2 = ProtobufHelper.FromBytes<SMSG_Auth_Logon_Proof_M2>(message);
  61. return smsgAuthLogonProofM2;
  62. }
  63. public async Task<SMSG_Realm_List> Handle_SMSG_Realm_List()
  64. {
  65. var result = await this.MessageChannel.RecvMessage();
  66. ushort opcode = result.Item1;
  67. byte[] message = result.Item2;
  68. if (opcode != MessageOpcode.SMSG_REALM_LIST)
  69. {
  70. throw new BossException(string.Format("session: {0}, error opcode: {1}", this.ID,
  71. opcode));
  72. }
  73. var smsgRealmList = ProtobufHelper.FromBytes<SMSG_Realm_List>(message);
  74. return smsgRealmList;
  75. }
  76. public async Task<Tuple<string, ushort, SRP6Client>> Login(string account, string password)
  77. {
  78. byte[] passwordBytes = password.ToByteArray();
  79. MD5 md5 = MD5.Create();
  80. byte[] passwordMd5 = md5.ComputeHash(passwordBytes);
  81. byte[] passwordMd5Hex = passwordMd5.ToHex().ToLower().ToByteArray();
  82. // 发送帐号和密码MD5
  83. var cmsgAuthLogonPermit = new CMSG_Auth_Logon_Permit
  84. {
  85. Account = account.ToByteArray(),
  86. PasswordMd5 = passwordMd5Hex
  87. };
  88. Log.Trace("session: {0}, account: {1}, password: {2}", this.ID,
  89. cmsgAuthLogonPermit.Account.ToStr(), cmsgAuthLogonPermit.PasswordMd5.ToHex());
  90. this.MessageChannel.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_PERMIT,
  91. cmsgAuthLogonPermit);
  92. var smsgPasswordProtectType = await this.Handle_SMSG_Password_Protect_Type();
  93. if (smsgPasswordProtectType.Code != 200)
  94. {
  95. throw new BossException(
  96. string.Format("session: {0}, SMSG_Password_Protect_Type: {1}", this.ID,
  97. MongoHelper.ToJson(smsgPasswordProtectType)));
  98. }
  99. // 这个消息已经没有作用,只用来保持原有的代码流程
  100. var cmsgAuthLogonChallenge = new CMSG_Auth_Logon_Challenge();
  101. this.MessageChannel.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_CHALLENGE,
  102. cmsgAuthLogonChallenge);
  103. var smsgAuthLogonChallengeResponse =
  104. await this.Handle_SMSG_Auth_Logon_Challenge_Response();
  105. if (smsgAuthLogonChallengeResponse.ErrorCode != ErrorCode.REALM_AUTH_SUCCESS)
  106. {
  107. throw new BossException(
  108. string.Format("session: {0}, SMSG_Auth_Logon_Challenge_Response: {1}",
  109. this.ID, MongoHelper.ToJson(smsgAuthLogonChallengeResponse)));
  110. }
  111. Log.Trace("session: {0}, SMSG_Auth_Logon_Challenge_Response OK", this.ID);
  112. // 以下是SRP6处理过程
  113. var n = smsgAuthLogonChallengeResponse.N.ToUBigInteger();
  114. var g = smsgAuthLogonChallengeResponse.G.ToUBigInteger();
  115. var b = smsgAuthLogonChallengeResponse.B.ToUBigInteger();
  116. var salt = smsgAuthLogonChallengeResponse.S.ToUBigInteger();
  117. var srp6Client = new SRP6Client(new SHA1Managed(), n, g, b, salt, account.ToByteArray(),
  118. passwordMd5Hex);
  119. Log.Debug("s: {0}\nN: {1}\nG: {2}\nB: {3}\nA: {4}\nS: {5}\nK: {6}\nm: {7}\na: {8}",
  120. srp6Client.Salt.ToUBigIntegerArray().ToHex(),
  121. srp6Client.N.ToUBigIntegerArray().ToHex(),
  122. srp6Client.G.ToUBigIntegerArray().ToHex(),
  123. srp6Client.B.ToUBigIntegerArray().ToHex(),
  124. srp6Client.A.ToUBigIntegerArray().ToHex(),
  125. srp6Client.S.ToUBigIntegerArray().ToHex(),
  126. srp6Client.K.ToUBigIntegerArray().ToHex(),
  127. srp6Client.M.ToUBigIntegerArray().ToHex(),
  128. srp6Client.SmallA.ToUBigIntegerArray().ToHex());
  129. var cmsgAuthLogonProof = new CMSG_Auth_Logon_Proof
  130. {
  131. A = srp6Client.A.ToUBigIntegerArray(),
  132. M = srp6Client.M.ToUBigIntegerArray()
  133. };
  134. this.MessageChannel.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_PROOF, cmsgAuthLogonProof);
  135. var smsgAuthLogonProofM2 = await this.Handle_SMSG_Auth_Logon_Proof_M2();
  136. if (smsgAuthLogonProofM2.ErrorCode != ErrorCode.REALM_AUTH_SUCCESS)
  137. {
  138. throw new BossException(string.Format(
  139. "session: {0}, SMSG_Auth_Logon_Proof_M2: {1}",
  140. this.ID, MongoHelper.ToJson(smsgAuthLogonProofM2)));
  141. }
  142. Log.Trace("session: {0}, SMSG_Auth_Logon_Proof_M2 OK", this.ID);
  143. // 请求realm list
  144. var cmsgRealmList = new CMSG_Realm_List();
  145. this.MessageChannel.SendMessage(MessageOpcode.CMSG_REALM_LIST, cmsgRealmList);
  146. var smsgRealmList = await this.Handle_SMSG_Realm_List();
  147. Log.Trace("session: {0}, SMSG_Realm_List OK", this.ID);
  148. string gateIP = smsgRealmList.GateIP;
  149. ushort gatePort = (ushort) smsgRealmList.GatePort;
  150. return Tuple.Create(gateIP, gatePort, srp6Client);
  151. }
  152. }
  153. }