public static void HandleAuthLogOnChallenge(IClient client, IncomingAuthPacket packet)
        {
            Contract.Requires(client != null);
            Contract.Requires(packet != null);

            packet.ReadByte(); // unk
            packet.ReadInt16(); // size
            packet.ReadFourCC(); // gameName
            packet.ReadByte(); // version1
            packet.ReadByte(); // version2
            packet.ReadByte(); // version3
            packet.ReadInt16(); // build
            packet.ReadFourCC(); // platform
            packet.ReadFourCC(); // os
            packet.ReadFourCC(); // country
            packet.ReadInt32(); // timeZoneBias
            packet.ReadInt32(); // ip
            var usernameLength = packet.ReadByte();
            var usernameBytes = packet.ReadBytes(usernameLength);
            var username = Encoding.ASCII.GetString(usernameBytes);
            SRPServer srpData = GetSRPDataForUserName(username);
            if (srpData == null)
            {
                SendAuthenticationChallengeFailure(client, AuthResult.FailUnknownAccount);
            }
            else
            {
                client.UserData.SRP = srpData;

                // make sure the result is at least 32 bytes long
                var peData = srpData.PublicEphemeralValueB.GetBytes(32);
                var publicEphemeral = new BigInteger(peData);

                var rand = new BigInteger(new FastRandom(), 16 * 8);
                SendAuthenticationChallengeSuccess(client,
                                                   publicEphemeral,
                                                   srpData.Parameters.Generator,
                                                   srpData.Parameters.Modulus,
                                                   srpData.Salt,
                                                   rand);
            }
        }
        public static void HandleReconnectChallenge(IClient client, IncomingAuthPacket packet)
        {
            // structure is the same as AuthenticationLogOnChallenge
            Contract.Requires(client != null);
            Contract.Requires(packet != null);

            packet.ReadByte(); // unk
            packet.ReadInt16(); // size
            packet.ReadFourCC(); // gameName
            packet.ReadByte(); // version1
            packet.ReadByte(); // version2
            packet.ReadByte(); // version3
            packet.ReadInt16(); // build
            packet.ReadFourCC(); // platform
            packet.ReadFourCC(); // os
            packet.ReadFourCC(); // country
            packet.ReadInt32(); // timeZoneBias
            packet.ReadInt32(); // ip
            var usernameLength = packet.ReadByte();
            var usernameBytes = packet.ReadBytes(usernameLength);
            Encoding.ASCII.GetString(usernameBytes); // username

            // TODO fetch this from the database (or some other persistent storage)
            BigInteger sessionKey = null;
            if (sessionKey == null) {
                client.Disconnect();
                return;
            }

            //BigInteger rand = new BigInteger(new FastRandom(), 16 * 8);
            //SendReconnectChallengeSuccess(client, rand);
            //client.UserData.ReconnectRand = rand;
            //client.UserData.Username = username;
        }