SRP6Client.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Linq;
  3. using System.Numerics;
  4. using System.Security.Cryptography;
  5. using Helper;
  6. using Log;
  7. namespace LoginClient
  8. {
  9. public class SRP6Client
  10. {
  11. private readonly BigInteger n; // N
  12. private readonly BigInteger g; // g
  13. private readonly BigInteger b; // B
  14. private readonly BigInteger a; // A
  15. private readonly BigInteger x; // X
  16. private readonly BigInteger u; // U
  17. private readonly BigInteger s; // S
  18. private readonly BigInteger k; // K
  19. private readonly BigInteger m; // M
  20. private readonly byte[] p;
  21. private readonly byte[] account;
  22. private readonly BigInteger salt; // s, 服务端发过来的salt
  23. private const int lowerK = 3;
  24. private readonly BigInteger smallA ;
  25. private readonly HashAlgorithm hashAlgorithm;
  26. public SRP6Client(
  27. HashAlgorithm hashAlgorithm, BigInteger n, BigInteger g, BigInteger b,
  28. BigInteger salt, byte[] account, byte[] passwordMd5Hex)
  29. {
  30. this.smallA = BigIntegerHelper.RandUnsignedBigInteger(19);
  31. this.hashAlgorithm = hashAlgorithm;
  32. this.n = n;
  33. this.g = g;
  34. this.b = b;
  35. this.salt = salt;
  36. this.account = account;
  37. this.p = hashAlgorithm.ComputeHash(new byte[0]
  38. .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. hashAlgorithm.Initialize();
  147. var joinBytes = new byte[0]
  148. .Concat(this.Salt.ToUBigIntegerArray())
  149. .Concat(this.P)
  150. .ToArray();
  151. return hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
  152. }
  153. /// <summary>
  154. /// 计算A: A = g ^ a % N
  155. /// </summary>
  156. /// <returns></returns>
  157. private BigInteger CalculateA()
  158. {
  159. return BigIntegerHelper.UModPow(this.G, this.SmallA, this.N);
  160. }
  161. /// <summary>
  162. /// 计算U: U = H(A, B)
  163. /// </summary>
  164. /// <returns></returns>
  165. private BigInteger CalculateU()
  166. {
  167. hashAlgorithm.Initialize();
  168. var joinBytes = new byte[0]
  169. .Concat(this.A.ToUBigIntegerArray(32))
  170. .Concat(this.B.ToUBigIntegerArray(32))
  171. .ToArray();
  172. return hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
  173. }
  174. /// <summary>
  175. /// 计算S: S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N);
  176. /// </summary>
  177. /// <returns></returns>
  178. private BigInteger CalculateS()
  179. {
  180. BigInteger s1 = this.B - BigIntegerHelper.UModPow(this.G, this.X, this.N) * lowerK;
  181. BigInteger s2 = this.SmallA + (this.U * this.X);
  182. BigInteger s3 = BigIntegerHelper.UModPow(s1, s2, this.N);
  183. return s3;
  184. }
  185. /// <summary>
  186. ///
  187. /// </summary>
  188. /// <returns></returns>
  189. private BigInteger CalculateK()
  190. {
  191. hashAlgorithm.Initialize();
  192. byte[] sBytes = this.S.ToUBigIntegerArray();
  193. int halfLength = sBytes.Length / 2;
  194. var kBytes = new byte[40];
  195. var halfS = new byte[halfLength];
  196. for (int i = 0; i < halfLength; ++i)
  197. {
  198. halfS[i] = sBytes[i * 2];
  199. }
  200. var p1 = hashAlgorithm.ComputeHash(halfS);
  201. for (int i = 0; i < 20; ++i)
  202. {
  203. kBytes[i * 2] = p1[i];
  204. }
  205. for (int i = 0; i < halfLength; ++i)
  206. {
  207. halfS[i] = sBytes[i * 2 + 1];
  208. }
  209. var p2 = hashAlgorithm.ComputeHash(halfS);
  210. for (int i = 0; i < 20; ++i)
  211. {
  212. kBytes[i * 2 + 1] = p2[i];
  213. }
  214. return kBytes.ToUBigInteger();
  215. }
  216. /// <summary>
  217. ///
  218. /// </summary>
  219. /// <returns></returns>
  220. private BigInteger CalculateM()
  221. {
  222. hashAlgorithm.Initialize();
  223. var hashN = hashAlgorithm.ComputeHash(this.N.ToUBigIntegerArray());
  224. var hashG = hashAlgorithm.ComputeHash(this.G.ToUBigIntegerArray());
  225. // 这里与标准srp6不一样,只异或了20个byte,实际上有32个byte
  226. for (var i = 0; i < 20; ++i)
  227. {
  228. hashN[i] ^= hashG[i];
  229. }
  230. var hashGXorhashN = hashN; // H(N) ^ H(g)
  231. var hashedIdentity = hashAlgorithm.ComputeHash(this.Account); // H(I)
  232. // H(H(N) ^ H(g), H(P), s, A, B, K_c)
  233. var mBytes = hashAlgorithm.ComputeHash(new byte[0]
  234. .Concat(hashGXorhashN)
  235. .Concat(hashedIdentity)
  236. .Concat(this.Salt.ToUBigIntegerArray(32))
  237. .Concat(this.A.ToUBigIntegerArray(32))
  238. .Concat(this.B.ToUBigIntegerArray(32))
  239. .Concat(this.K.ToUBigIntegerArray(40))
  240. .ToArray());
  241. return mBytes.ToUBigInteger();
  242. }
  243. public byte[] CalculateGateDigest(uint clientSeed, uint serverSeed)
  244. {
  245. hashAlgorithm.Initialize();
  246. var digest = hashAlgorithm.ComputeHash(new byte[0]
  247. .Concat(this.Account)
  248. .Concat(new byte[4] { 0, 0, 0, 0 })
  249. .Concat(BitConverter.GetBytes(clientSeed))
  250. .Concat(BitConverter.GetBytes(serverSeed))
  251. .Concat(k.ToUBigIntegerArray())
  252. .ToArray());
  253. return digest;
  254. }
  255. }
  256. }