| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- using System;
- using System.Linq;
- using System.Numerics;
- using System.Security.Cryptography;
- using Helper;
- namespace BossClient
- {
- 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 BigInteger m; // M
- private readonly byte[] p;
- private readonly byte[] account;
- private readonly BigInteger salt; // s, 服务端发过来的salt
- private const int lowerK = 3;
- private readonly BigInteger smallA;
- private readonly HashAlgorithm hashAlgorithm;
- public SRP6Client(
- HashAlgorithm hashAlgorithm, BigInteger n, BigInteger g, BigInteger b,
- BigInteger salt, byte[] account, byte[] passwordMd5Hex)
- {
- this.smallA = BigIntegerHelper.RandUnsignedBigInteger(19);
- this.hashAlgorithm = hashAlgorithm;
- this.n = n;
- this.g = g;
- this.b = b;
- this.salt = salt;
- this.account = account;
- this.p =
- hashAlgorithm.ComputeHash(
- new byte[0].Concat(account)
- .Concat(new[] { (byte) ':' })
- .Concat(passwordMd5Hex)
- .ToArray());
- 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(); // H(H(N) ^ H(g), H(P), s, A, B, K)
- }
- 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 BigInteger M
- {
- get
- {
- return this.m;
- }
- }
- public byte[] P
- {
- get
- {
- return this.p;
- }
- }
- public BigInteger Salt
- {
- get
- {
- return this.salt;
- }
- }
- public BigInteger SmallA
- {
- get
- {
- return this.smallA;
- }
- }
- public byte[] Account
- {
- get
- {
- return this.account;
- }
- }
- /// <summary>
- /// 计算X: X = H(s, P)
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateX()
- {
- this.hashAlgorithm.Initialize();
- var joinBytes =
- new byte[0].Concat(this.Salt.ToUBigIntegerArray()).Concat(this.P).ToArray();
- return this.hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
- }
- /// <summary>
- /// 计算A: A = g ^ a % N
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateA()
- {
- return BigIntegerHelper.UModPow(this.G, this.SmallA, this.N);
- }
- /// <summary>
- /// 计算U: U = H(A, B)
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateU()
- {
- this.hashAlgorithm.Initialize();
- var joinBytes =
- new byte[0].Concat(this.A.ToUBigIntegerArray(32))
- .Concat(this.B.ToUBigIntegerArray(32))
- .ToArray();
- return this.hashAlgorithm.ComputeHash(joinBytes).ToUBigInteger();
- }
- /// <summary>
- /// 计算S: S = (B - (k * g.ModExp(x, N))).ModExp(a + (u * x), N);
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateS()
- {
- BigInteger s1 = this.B - BigIntegerHelper.UModPow(this.G, this.X, this.N) * lowerK;
- BigInteger s2 = this.SmallA + (this.U * this.X);
- BigInteger s3 = BigIntegerHelper.UModPow(s1, s2, this.N);
- return s3;
- }
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateK()
- {
- this.hashAlgorithm.Initialize();
- byte[] sBytes = this.S.ToUBigIntegerArray();
- int halfLength = sBytes.Length / 2;
- var kBytes = new byte[40];
- var halfS = new byte[halfLength];
- for (int i = 0; i < halfLength; ++i)
- {
- halfS[i] = sBytes[i * 2];
- }
- var p1 = this.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 = this.hashAlgorithm.ComputeHash(halfS);
- for (int i = 0; i < 20; ++i)
- {
- kBytes[i * 2 + 1] = p2[i];
- }
- return kBytes.ToUBigInteger();
- }
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- private BigInteger CalculateM()
- {
- this.hashAlgorithm.Initialize();
- var hashN = this.hashAlgorithm.ComputeHash(this.N.ToUBigIntegerArray());
- var hashG = this.hashAlgorithm.ComputeHash(this.G.ToUBigIntegerArray());
- // 这里与标准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 = this.hashAlgorithm.ComputeHash(this.Account); // H(I)
- // H(H(N) ^ H(g), H(P), s, A, B, K_c)
- var mBytes =
- this.hashAlgorithm.ComputeHash(
- new byte[0].Concat(hashGXorhashN)
- .Concat(hashedIdentity)
- .Concat(this.Salt.ToUBigIntegerArray(32))
- .Concat(this.A.ToUBigIntegerArray(32))
- .Concat(this.B.ToUBigIntegerArray(32))
- .Concat(this.K.ToUBigIntegerArray(40))
- .ToArray());
- return mBytes.ToUBigInteger();
- }
- public byte[] CalculateGateDigest(uint clientSeed, uint serverSeed)
- {
- this.hashAlgorithm.Initialize();
- var digest =
- this.hashAlgorithm.ComputeHash(
- new byte[0].Concat(this.Account)
- .Concat(new byte[4] { 0, 0, 0, 0 })
- .Concat(BitConverter.GetBytes(clientSeed))
- .Concat(BitConverter.GetBytes(serverSeed))
- .Concat(this.k.ToUBigIntegerArray())
- .ToArray());
- return digest;
- }
- }
- }
|