SRP6Client.cs 5.2 KB

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