SRP6Client.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Linq;
  3. using System.Numerics;
  4. using System.Security.Cryptography;
  5. using Helper;
  6. namespace BossClient
  7. {
  8. public class SRP6Client
  9. {
  10. private readonly BigInteger n; // N
  11. private readonly BigInteger g; // g
  12. private readonly BigInteger b; // B
  13. private readonly BigInteger a; // A
  14. private readonly BigInteger x; // X
  15. private readonly BigInteger u; // U
  16. private readonly BigInteger s; // S
  17. private readonly BigInteger k; // K
  18. private readonly BigInteger m; // M
  19. private readonly byte[] p;
  20. private readonly byte[] account;
  21. private readonly BigInteger salt; // s, 服务端发过来的salt
  22. private const int lowerK = 3;
  23. private readonly BigInteger smallA;
  24. private readonly HashAlgorithm hashAlgorithm;
  25. public SRP6Client(
  26. HashAlgorithm hashAlgorithm, BigInteger n, BigInteger g, BigInteger b,
  27. BigInteger salt, byte[] account, byte[] passwordMd5Hex)
  28. {
  29. this.smallA = BigIntegerHelper.RandUnsignedBigInteger(19);
  30. this.hashAlgorithm = hashAlgorithm;
  31. this.n = n;
  32. this.g = g;
  33. this.b = b;
  34. this.salt = salt;
  35. this.account = account;
  36. this.p =
  37. hashAlgorithm.ComputeHash(
  38. new byte[0].Concat(account)
  39. .Concat(new[] { (byte) ':' })
  40. .Concat(passwordMd5Hex)
  41. .ToArray());
  42. this.a = this.CalculateA(); // A = g ^ a % N
  43. this.x = this.CalculateX(); // X = H(s, P)
  44. this.u = this.CalculateU(); // U = H(A, B)
  45. this.s = this.CalculateS(); // S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N)
  46. this.k = this.CalculateK();
  47. this.m = this.CalculateM(); // H(H(N) ^ H(g), H(P), s, A, B, K)
  48. }
  49. public BigInteger N
  50. {
  51. get
  52. {
  53. return this.n;
  54. }
  55. }
  56. public BigInteger G
  57. {
  58. get
  59. {
  60. return this.g;
  61. }
  62. }
  63. public BigInteger B
  64. {
  65. get
  66. {
  67. return this.b;
  68. }
  69. }
  70. public BigInteger A
  71. {
  72. get
  73. {
  74. return this.a;
  75. }
  76. }
  77. public BigInteger X
  78. {
  79. get
  80. {
  81. return this.x;
  82. }
  83. }
  84. public BigInteger U
  85. {
  86. get
  87. {
  88. return this.u;
  89. }
  90. }
  91. public BigInteger S
  92. {
  93. get
  94. {
  95. return this.s;
  96. }
  97. }
  98. public BigInteger K
  99. {
  100. get
  101. {
  102. return this.k;
  103. }
  104. }
  105. public BigInteger M
  106. {
  107. get
  108. {
  109. return this.m;
  110. }
  111. }
  112. public byte[] P
  113. {
  114. get
  115. {
  116. return this.p;
  117. }
  118. }
  119. public BigInteger Salt
  120. {
  121. get
  122. {
  123. return this.salt;
  124. }
  125. }
  126. public BigInteger SmallA
  127. {
  128. get
  129. {
  130. return this.smallA;
  131. }
  132. }
  133. public byte[] Account
  134. {
  135. get
  136. {
  137. return this.account;
  138. }
  139. }
  140. /// <summary>
  141. /// 计算X: X = H(s, P)
  142. /// </summary>
  143. /// <returns></returns>
  144. private BigInteger CalculateX()
  145. {
  146. this.hashAlgorithm.Initialize();
  147. var joinBytes =
  148. new byte[0].Concat(this.Salt.ToUBigIntegerArray()).Concat(this.P).ToArray();
  149. return this.hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
  150. }
  151. /// <summary>
  152. /// 计算A: A = g ^ a % N
  153. /// </summary>
  154. /// <returns></returns>
  155. private BigInteger CalculateA()
  156. {
  157. return BigIntegerHelper.UModPow(this.G, this.SmallA, this.N);
  158. }
  159. /// <summary>
  160. /// 计算U: U = H(A, B)
  161. /// </summary>
  162. /// <returns></returns>
  163. private BigInteger CalculateU()
  164. {
  165. this.hashAlgorithm.Initialize();
  166. var joinBytes =
  167. new byte[0].Concat(this.A.ToUBigIntegerArray(32))
  168. .Concat(this.B.ToUBigIntegerArray(32))
  169. .ToArray();
  170. return this.hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
  171. }
  172. /// <summary>
  173. /// 计算S: S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N);
  174. /// </summary>
  175. /// <returns></returns>
  176. private BigInteger CalculateS()
  177. {
  178. BigInteger s1 = this.B - BigIntegerHelper.UModPow(this.G, this.X, this.N) * lowerK;
  179. BigInteger s2 = this.SmallA + (this.U * this.X);
  180. BigInteger s3 = BigIntegerHelper.UModPow(s1, s2, this.N);
  181. return s3;
  182. }
  183. /// <summary>
  184. ///
  185. /// </summary>
  186. /// <returns></returns>
  187. private BigInteger CalculateK()
  188. {
  189. this.hashAlgorithm.Initialize();
  190. byte[] sBytes = this.S.ToUBigIntegerArray();
  191. int halfLength = sBytes.Length / 2;
  192. var kBytes = new byte[40];
  193. var halfS = new byte[halfLength];
  194. for (int i = 0; i < halfLength; ++i)
  195. {
  196. halfS[i] = sBytes[i * 2];
  197. }
  198. var p1 = this.hashAlgorithm.ComputeHash(halfS);
  199. for (int i = 0; i < 20; ++i)
  200. {
  201. kBytes[i * 2] = p1[i];
  202. }
  203. for (int i = 0; i < halfLength; ++i)
  204. {
  205. halfS[i] = sBytes[i * 2 + 1];
  206. }
  207. var p2 = this.hashAlgorithm.ComputeHash(halfS);
  208. for (int i = 0; i < 20; ++i)
  209. {
  210. kBytes[i * 2 + 1] = p2[i];
  211. }
  212. return kBytes.ToUBigInteger();
  213. }
  214. /// <summary>
  215. ///
  216. /// </summary>
  217. /// <returns></returns>
  218. private BigInteger CalculateM()
  219. {
  220. this.hashAlgorithm.Initialize();
  221. var hashN = this.hashAlgorithm.ComputeHash(this.N.ToUBigIntegerArray());
  222. var hashG = this.hashAlgorithm.ComputeHash(this.G.ToUBigIntegerArray());
  223. // 这里与标准srp6不一样,只异或了20个byte,实际上有32个byte
  224. for (var i = 0; i < 20; ++i)
  225. {
  226. hashN[i] ^= hashG[i];
  227. }
  228. var hashGXorhashN = hashN; // H(N) ^ H(g)
  229. var hashedIdentity = this.hashAlgorithm.ComputeHash(this.Account); // H(I)
  230. // H(H(N) ^ H(g), H(P), s, A, B, K_c)
  231. var mBytes =
  232. this.hashAlgorithm.ComputeHash(
  233. new byte[0].Concat(hashGXorhashN)
  234. .Concat(hashedIdentity)
  235. .Concat(this.Salt.ToUBigIntegerArray(32))
  236. .Concat(this.A.ToUBigIntegerArray(32))
  237. .Concat(this.B.ToUBigIntegerArray(32))
  238. .Concat(this.K.ToUBigIntegerArray(40))
  239. .ToArray());
  240. return mBytes.ToUBigInteger();
  241. }
  242. public byte[] CalculateGateDigest(uint clientSeed, uint serverSeed)
  243. {
  244. this.hashAlgorithm.Initialize();
  245. var digest =
  246. this.hashAlgorithm.ComputeHash(
  247. new byte[0].Concat(this.Account)
  248. .Concat(new byte[4] { 0, 0, 0, 0 })
  249. .Concat(BitConverter.GetBytes(clientSeed))
  250. .Concat(BitConverter.GetBytes(serverSeed))
  251. .Concat(this.k.ToUBigIntegerArray())
  252. .ToArray());
  253. return digest;
  254. }
  255. }
  256. }