SRP6Client.cs 5.2 KB

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