SRP6Client.cs 5.1 KB

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