RealmSession.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Threading.Tasks;
  4. using Helper;
  5. using Log;
  6. namespace BossClient
  7. {
  8. public class RealmSession: IDisposable
  9. {
  10. public int ID { get; set; }
  11. public IMessageChannel MessageChannel { get; set; }
  12. public RealmSession(int id, IMessageChannel messageChannel)
  13. {
  14. this.ID = id;
  15. this.MessageChannel = messageChannel;
  16. }
  17. public void Dispose()
  18. {
  19. this.MessageChannel.Dispose();
  20. }
  21. public async Task<SMSG_Password_Protect_Type> Handle_SMSG_Password_Protect_Type()
  22. {
  23. var result = await this.MessageChannel.RecvMessage();
  24. ushort opcode = result.Item1;
  25. byte[] message = result.Item2;
  26. if (opcode != MessageOpcode.SMSG_PASSWORD_PROTECT_TYPE)
  27. {
  28. throw new BossException(string.Format(
  29. "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. Logger.Trace("opcode: {0}", opcode);
  44. throw new BossException(string.Format(
  45. "session: {0}, opcode: {1}", this.ID, opcode));
  46. }
  47. var smsgAuthLogonChallengeResponse =
  48. ProtobufHelper.FromBytes<SMSG_Auth_Logon_Challenge_Response>(message);
  49. return smsgAuthLogonChallengeResponse;
  50. }
  51. public async Task<SMSG_Auth_Logon_Proof_M2> Handle_SMSG_Auth_Logon_Proof_M2()
  52. {
  53. var result = await this.MessageChannel.RecvMessage();
  54. ushort opcode = result.Item1;
  55. byte[] message = result.Item2;
  56. if (opcode != MessageOpcode.SMSG_AUTH_LOGON_PROOF_M2)
  57. {
  58. throw new BossException(string.Format(
  59. "session: {0}, error opcode: {1}", this.ID, opcode));
  60. }
  61. var smsgAuthLogonProofM2 = ProtobufHelper.FromBytes<SMSG_Auth_Logon_Proof_M2>(message);
  62. return smsgAuthLogonProofM2;
  63. }
  64. public async Task<SMSG_Realm_List> Handle_SMSG_Realm_List()
  65. {
  66. var result = await this.MessageChannel.RecvMessage();
  67. ushort opcode = result.Item1;
  68. byte[] message = result.Item2;
  69. if (opcode != MessageOpcode.SMSG_REALM_LIST)
  70. {
  71. throw new BossException(string.Format(
  72. "session: {0}, error opcode: {1}", this.ID, opcode));
  73. }
  74. var smsgRealmList = ProtobufHelper.FromBytes<SMSG_Realm_List>(message);
  75. return smsgRealmList;
  76. }
  77. public async Task<Tuple<string, ushort, SRP6Client>> Login(string account, string password)
  78. {
  79. byte[] passwordBytes = password.ToByteArray();
  80. MD5 md5 = MD5.Create();
  81. byte[] passwordMd5 = md5.ComputeHash(passwordBytes);
  82. byte[] passwordMd5Hex = passwordMd5.ToHex().ToLower().ToByteArray();
  83. // 发送帐号和密码MD5
  84. var cmsgAuthLogonPermit = new CMSG_Auth_Logon_Permit
  85. {
  86. Account = account.ToByteArray(),
  87. PasswordMd5 = passwordMd5Hex
  88. };
  89. Logger.Trace("session: {0}, account: {1}, password: {2}", this.ID,
  90. cmsgAuthLogonPermit.Account.ToStr(), cmsgAuthLogonPermit.PasswordMd5.ToHex());
  91. this.MessageChannel.SendMessage(MessageOpcode.CMSG_AUTH_LOGON_PERMIT, cmsgAuthLogonPermit);
  92. var smsgPasswordProtectType = await this.Handle_SMSG_Password_Protect_Type();
  93. if (smsgPasswordProtectType.Code != 200)
  94. {
  95. throw new BossException(string.Format(
  96. "session: {0}, SMSG_Password_Protect_Type: {1}",
  97. this.ID, JsonHelper.ToString(smsgPasswordProtectType)));
  98. }
  99. // 这个消息已经没有作用,只用来保持原有的代码流程
  100. var cmsgAuthLogonChallenge = new CMSG_Auth_Logon_Challenge();
  101. this.MessageChannel.SendMessage(
  102. MessageOpcode.CMSG_AUTH_LOGON_CHALLENGE, 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, JsonHelper.ToString(smsgAuthLogonChallengeResponse)));
  110. }
  111. Logger.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(
  118. new SHA1Managed(), n, g, b, salt, account.ToByteArray(), passwordMd5Hex);
  119. Logger.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, JsonHelper.ToString(smsgAuthLogonProofM2)));
  141. }
  142. Logger.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. Logger.Trace("session: {0}, SMSG_Realm_List OK", this.ID);
  148. string address = smsgRealmList.GateList[0].Address.ToStr();
  149. string[] split = address.Split(new[] { ':' });
  150. if (split.Length != 2)
  151. {
  152. throw new BossException(
  153. string.Format("session: {0}, gate address error, address: {1}",
  154. this.ID, address));
  155. }
  156. string gateIP = split[0];
  157. ushort gatePort = UInt16.Parse(split[1]);
  158. return Tuple.Create(gateIP, gatePort, srp6Client);
  159. }
  160. }
  161. }