using System; using System.Globalization; using System.Linq; using System.Numerics; using System.Security.Cryptography; using Helper; namespace Robot { public class SRP6Client { private readonly BigInteger n; // N private readonly BigInteger g; // g private readonly BigInteger b; // B private readonly BigInteger a; // A private readonly BigInteger x; // X private readonly BigInteger u; // U private readonly BigInteger s; // S private readonly BigInteger k; // K private readonly byte[] m; // M private readonly byte[] p; private readonly string account; private readonly BigInteger salt; // s, 服务端发过来的salt private const int lowerK = 3; private readonly HashAlgorithm hashAlgorithm; public SRP6Client( HashAlgorithm hashAlgorithm, BigInteger n, BigInteger g, BigInteger b, BigInteger salt, string account, string password) { this.hashAlgorithm = hashAlgorithm; this.n = n; this.g = g; this.b = b; this.salt = salt; this.account = account; string identity = account + ":" + password; this.p = hashAlgorithm.ComputeHash(identity.ToByteArray()); this.a = this.CalculateA(); // A = g ^ a % N this.x = this.CalculateX(); // X = H(s, P) this.u = this.CalculateU(); // U = H(A, B) this.s = this.CalculateS(); // S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N) this.k = this.CalculateK(); this.m = this.CalculateM(); // } public BigInteger N { get { return this.n; } } public BigInteger G { get { return this.g; } } public BigInteger B { get { return this.b; } } public BigInteger A { get { return this.a; } } public BigInteger X { get { return this.x; } } public BigInteger U { get { return this.u; } } public BigInteger S { get { return this.s; } } public BigInteger K { get { return this.k; } } public byte[] M { get { return this.m; } } public byte[] P { get { return this.p; } } /// /// 计算X: X = H(s, P) /// /// private BigInteger CalculateX() { hashAlgorithm.Initialize(); var joinBytes = new byte[0] .Concat(salt.ToTrimByteArray()) .Concat(this.P) .ToArray(); return hashAlgorithm.ComputeHash(joinBytes).ToUnsignedBigInteger(); } /// /// 计算A: A = g ^ a % N /// /// private BigInteger CalculateA() { BigInteger randomA = BigIntegerHelper.RandUnsignedBigInteger(19); BigInteger calculatA = BigInteger.ModPow(this.G, randomA, this.N); return calculatA; } /// /// 计算U: U = H(A, B) /// /// private BigInteger CalculateU() { hashAlgorithm.Initialize(); var joinBytes = new byte[0] .Concat(this.A.ToTrimByteArray()) .Concat(this.B.ToTrimByteArray()) .ToArray(); return hashAlgorithm.ComputeHash(joinBytes).ToUnsignedBigInteger(); } /// /// 计算S: S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N); /// /// private BigInteger CalculateS() { BigInteger s1 = this.B - BigInteger.ModPow(this.G, this.X, this.N) * lowerK; BigInteger s2 = this.A + (this.U * this.X); return BigInteger.ModPow(s1, s2, this.N); } /// /// /// /// private BigInteger CalculateK() { hashAlgorithm.Initialize(); byte[] sBytes = this.S.ToTrimByteArray(); int sLength = sBytes.Length; int halfLength = sLength / 2; var kBytes = new byte[40]; var halfS = new byte[sLength]; for (int i = 0; i < halfLength; ++i) { halfS[i] = sBytes[i * 2]; } var p1 = hashAlgorithm.ComputeHash(halfS); for (int i = 0; i < 20; ++i) { kBytes[i * 2] = p1[i]; } for (int i = 0; i < halfLength; ++i) { halfS[i] = sBytes[i * 2 + 1]; } var p2 = hashAlgorithm.ComputeHash(halfS); for (int i = 0; i < 20; ++i) { kBytes[i * 2 + 1] = p2[i]; } return kBytes.ToUnsignedBigInteger(); } /// /// /// /// private Byte[] CalculateM() { hashAlgorithm.Initialize(); var hashN = hashAlgorithm.ComputeHash(this.N.ToTrimByteArray()); var hashG = hashAlgorithm.ComputeHash(this.G.ToTrimByteArray()); // 这里与标准srp6不一样,只异或了20个byte,实际上有32个byte for (var i = 0; i < 20; ++i) { hashN[i] ^= hashG[i]; } var hashGXorhashN = hashN; // H(N) ^ H(g) var hashedIdentity = hashAlgorithm.ComputeHash(this.account.ToByteArray()); // H(I) // H(H(N) ^ H(g), H(P), s, A, B, K_c) var calculateM = hashAlgorithm.ComputeHash(new byte[0] .Concat(hashGXorhashN) .Concat(hashedIdentity) .Concat(this.salt.ToTrimByteArray()) .Concat(this.A.ToTrimByteArray()) .Concat(this.B.ToTrimByteArray()) .Concat(this.K.ToTrimByteArray()) .ToArray()); var copyM = new byte[20]; Array.Copy(calculateM, copyM, copyM.Length); return calculateM; } } }