SRP6Client.cs 5.7 KB

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