Example #1
0
        void HandleRealmLogonChallenge()
        {
            ServerAuthChallenge challenge = new ServerAuthChallenge(new BinaryReader(connection.GetStream()));

            switch (challenge.error)
            {
            case AuthResult.SUCCESS:
            {
                Game.UI.LogDebug("Received logon challenge");

                BigInteger N, A, B, a, u, x, S, salt, unk1, g, k;
                k = new BigInteger(3);

                #region Receive and initialize

                B    = challenge.B.ToBigInteger();             // server public key
                g    = challenge.g.ToBigInteger();
                N    = challenge.N.ToBigInteger();             // modulus
                salt = challenge.salt.ToBigInteger();
                unk1 = challenge.unk3.ToBigInteger();

                Game.UI.LogDebug("---====== Received from server: ======---");
                Game.UI.LogDebug(string.Format("B={0}", B.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("N={0}", N.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("salt={0}", challenge.salt.ToHexString()));

                #endregion

                #region Hash password

                x = HashAlgorithm.SHA1.Hash(challenge.salt, PasswordHash).ToBigInteger();

                Game.UI.LogDebug("---====== shared password hash ======---");
                Game.UI.LogDebug(string.Format("g={0}", g.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("x={0}", x.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("N={0}", N.ToCleanByteArray().ToHexString()));

                #endregion

                #region Create random key pair

                var rand = System.Security.Cryptography.RandomNumberGenerator.Create();

                do
                {
                    byte[] randBytes = new byte[19];
                    rand.GetBytes(randBytes);
                    a = randBytes.ToBigInteger();

                    A = g.ModPow(a, N);
                } while (A.ModPow(1, N) == 0);

                Game.UI.LogDebug("---====== Send data to server: ======---");
                Game.UI.LogDebug(string.Format("A={0}", A.ToCleanByteArray().ToHexString()));

                #endregion

                #region Compute session key

                u = HashAlgorithm.SHA1.Hash(A.ToCleanByteArray(), B.ToCleanByteArray()).ToBigInteger();

                // compute session key
                S = ((B + k * (N - g.ModPow(x, N))) % N).ModPow(a + (u * x), N);
                byte[] keyHash;
                byte[] sData = S.ToCleanByteArray();
                if (sData.Length < 32)
                {
                    var tmpBuffer = new byte[32];
                    Buffer.BlockCopy(sData, 0, tmpBuffer, 32 - sData.Length, sData.Length);
                    sData = tmpBuffer;
                }
                byte[] keyData = new byte[40];
                byte[] temp    = new byte[16];

                // take every even indices byte, hash, store in even indices
                for (int i = 0; i < 16; ++i)
                {
                    temp[i] = sData[i * 2];
                }
                keyHash = HashAlgorithm.SHA1.Hash(temp);
                for (int i = 0; i < 20; ++i)
                {
                    keyData[i * 2] = keyHash[i];
                }

                // do the same for odd indices
                for (int i = 0; i < 16; ++i)
                {
                    temp[i] = sData[i * 2 + 1];
                }
                keyHash = HashAlgorithm.SHA1.Hash(temp);
                for (int i = 0; i < 20; ++i)
                {
                    keyData[i * 2 + 1] = keyHash[i];
                }

                Key = keyData.ToBigInteger();

                Game.UI.LogDebug("---====== Compute session key ======---");
                Game.UI.LogDebug(string.Format("u={0}", u.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("S={0}", S.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("K={0}", Key.ToCleanByteArray().ToHexString()));

                #endregion

                #region Generate crypto proof

                // XOR the hashes of N and g together
                byte[] gNHash = new byte[20];

                byte[] nHash = HashAlgorithm.SHA1.Hash(N.ToCleanByteArray());
                for (int i = 0; i < 20; ++i)
                {
                    gNHash[i] = nHash[i];
                }
                Game.UI.LogDebug(string.Format("nHash={0}", nHash.ToHexString()));

                byte[] gHash = HashAlgorithm.SHA1.Hash(g.ToCleanByteArray());
                for (int i = 0; i < 20; ++i)
                {
                    gNHash[i] ^= gHash[i];
                }
                Game.UI.LogDebug(string.Format("gHash={0}", gHash.ToHexString()));

                // hash username
                byte[] userHash = HashAlgorithm.SHA1.Hash(Encoding.ASCII.GetBytes(Username));

                // our proof
                byte[] m1Hash = HashAlgorithm.SHA1.Hash
                                (
                    gNHash,
                    userHash,
                    challenge.salt,
                    A.ToCleanByteArray(),
                    B.ToCleanByteArray(),
                    Key.ToCleanByteArray()
                                );

                Game.UI.LogDebug("---====== Client proof: ======---");
                Game.UI.LogDebug(string.Format("gNHash={0}", gNHash.ToHexString()));
                Game.UI.LogDebug(string.Format("userHash={0}", userHash.ToHexString()));
                Game.UI.LogDebug(string.Format("salt={0}", challenge.salt.ToHexString()));
                Game.UI.LogDebug(string.Format("A={0}", A.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("B={0}", B.ToCleanByteArray().ToHexString()));
                Game.UI.LogDebug(string.Format("key={0}", Key.ToCleanByteArray().ToHexString()));

                Game.UI.LogDebug("---====== Send proof to server: ======---");
                Game.UI.LogDebug(string.Format("M={0}", m1Hash.ToHexString()));

                // expected proof for server
                m2 = HashAlgorithm.SHA1.Hash(A.ToCleanByteArray(), m1Hash, keyData);

                #endregion

                #region Send proof

                ClientAuthProof proof = new ClientAuthProof()
                {
                    A   = A.ToCleanByteArray(),
                    M1  = m1Hash,
                    crc = new byte[20],
                };

                Game.UI.LogDebug("Sending logon proof");
                proof.Send(stream);

                #endregion

                break;
            }

            case AuthResult.NO_MATCH:
                Game.UI.LogLine("Unknown account name", LogLevel.Error);
                break;

            case AuthResult.ACCOUNT_IN_USE:
                Game.UI.LogLine("Account already logged in", LogLevel.Error);
                break;

            case AuthResult.WRONG_BUILD_NUMBER:
                Game.UI.LogLine("Wrong build number", LogLevel.Error);
                break;
            }

            // get next command
            ReadCommand();
        }
Example #2
0
        void HandleRealmLogonChallenge()
        {
            ServerAuthChallenge challenge = new ServerAuthChallenge(new BinaryReader(connection.GetStream()));

            switch (challenge.error)
            {
                case AuthResult.SUCCESS:
                {
                    Game.UI.LogLine("Received logon challenge", LogLevel.Debug);

                    BigInteger N, A, B, a, u, x, S, salt, unk1, g, k;
                    k = new BigInteger(3);

                    #region Receive and initialize

                    B = challenge.B.ToBigInteger();			// server public key
                    g = challenge.g.ToBigInteger();
                    N = challenge.N.ToBigInteger();			// modulus
                    salt = challenge.salt.ToBigInteger();
                    unk1 = challenge.unk3.ToBigInteger();

                    Game.UI.LogLine("---====== Received from server: ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("B={0}", B.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("N={0}", N.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("salt={0}", challenge.salt.ToHexString()), LogLevel.Debug);

                    #endregion

                    #region Hash password

                    x = HashAlgorithm.SHA1.Hash(challenge.salt, PasswordHash).ToBigInteger();

                    Game.UI.LogLine("---====== shared password hash ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("g={0}", g.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("x={0}", x.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("N={0}", N.ToCleanByteArray().ToHexString()), LogLevel.Debug);

                    #endregion

                    #region Create random key pair

                    var rand = System.Security.Cryptography.RandomNumberGenerator.Create();

                    do
                    {
                        byte[] randBytes = new byte[19];
                        rand.GetBytes(randBytes);
                        a = randBytes.ToBigInteger();

                        A = g.ModPow(a, N);
                    } while (A.ModPow(1, N) == 0);

                    Game.UI.LogLine("---====== Send data to server: ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("A={0}", A.ToCleanByteArray().ToHexString()), LogLevel.Debug);

                    #endregion

                    #region Compute session key

                    u = HashAlgorithm.SHA1.Hash(A.ToCleanByteArray(), B.ToCleanByteArray()).ToBigInteger();

                    // compute session key
                    // TODO: session key computation fails for some reason
                    //     all variables match exactly to the server side, but
                    //     S is different
                    S = (B - k * g.ModPow(x, N)).ModPow(a + u * x, N);

                    byte[] keyHash;
                    byte[] sData = S.ToCleanByteArray();
                    byte[] keyData = new byte[40];
                    byte[] temp = new byte[16];

                    // take every even indices byte, hash, store in even indices
                    for (int i = 0; i < 16; ++i)
                        temp[i] = sData[i * 2];
                    keyHash = HashAlgorithm.SHA1.Hash(temp);
                    for (int i = 0; i < 20; ++i)
                        keyData[i * 2] = keyHash[i];

                    // do the same for odd indices
                    for (int i = 0; i < 16; ++i)
                        temp[i] = sData[i * 2 + 1];
                    keyHash = HashAlgorithm.SHA1.Hash(temp);
                    for (int i = 0; i < 20; ++i)
                        keyData[i * 2 + 1] = keyHash[i];

                    Key = keyData.ToBigInteger();

                    Game.UI.LogLine("---====== Compute session key ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("u={0}", u.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("S={0}", S.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("K={0}", Key.ToCleanByteArray().ToHexString()), LogLevel.Debug);

                    #endregion

                    #region Generate crypto proof

                    // XOR the hashes of N and g together
                    byte[] gNHash = new byte[20];

                    byte[] nHash = HashAlgorithm.SHA1.Hash(N.ToCleanByteArray());
                    for (int i = 0; i < 20; ++i)
                        gNHash[i] = nHash[i];
                    Game.UI.LogLine(string.Format("nHash={0}", nHash.ToHexString()), LogLevel.Debug);

                    byte[] gHash = HashAlgorithm.SHA1.Hash(g.ToCleanByteArray());
                    for (int i = 0; i < 20; ++i)
                        gNHash[i] ^= gHash[i];
                    Game.UI.LogLine(string.Format("gHash={0}", gHash.ToHexString()), LogLevel.Debug);

                    // hash username
                    byte[] userHash = HashAlgorithm.SHA1.Hash(Encoding.ASCII.GetBytes(Username));

                    // our proof
                    byte[] m1Hash = HashAlgorithm.SHA1.Hash
                    (
                        gNHash,
                        userHash,
                        challenge.salt,
                        A.ToCleanByteArray(),
                        B.ToCleanByteArray(),
                        Key.ToCleanByteArray()
                    );

                    Game.UI.LogLine("---====== Client proof: ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("gNHash={0}", gNHash.ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("userHash={0}", userHash.ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("salt={0}", challenge.salt.ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("A={0}", A.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("B={0}", B.ToCleanByteArray().ToHexString()), LogLevel.Debug);
                    Game.UI.LogLine(string.Format("key={0}", Key.ToCleanByteArray().ToHexString()), LogLevel.Debug);

                    Game.UI.LogLine("---====== Send proof to server: ======---", LogLevel.Debug);
                    Game.UI.LogLine(string.Format("M={0}", m1Hash.ToHexString()), LogLevel.Debug);

                    // expected proof for server
                    m2 = HashAlgorithm.SHA1.Hash(A.ToCleanByteArray(), m1Hash, keyData);

                    #endregion

                    #region Send proof

                    ClientAuthProof proof = new ClientAuthProof()
                    {
                        A = A.ToCleanByteArray(),
                        M1 = m1Hash,
                        crc = new byte[20],
                    };

                    Game.UI.LogLine("Sending logon proof", LogLevel.Debug);
                    proof.Send(output);

                    #endregion

                    break;
                }
                case AuthResult.NO_MATCH:
                    Game.UI.LogLine("Unknown account name", LogLevel.Error);
                    break;
                case AuthResult.ACCOUNT_IN_USE:
                    Game.UI.LogLine("Account already logged in", LogLevel.Error);
                    break;
                case AuthResult.WRONG_BUILD_NUMBER:
                    Game.UI.LogLine("Wrong build number", LogLevel.Error);
                    break;
            }

            // get next command
            ReadCommand();
        }