/// <summary>
        /// Process the second server challenge
        /// </summary>
        /// <param name="challenge">Server issued challenge</param>
        /// <returns>The client response</returns>
        private byte[] OnFinalResponse(byte[] challenge)
        {
            DigestChallenge dch =
                DigestChallenge.Parse(_encoding.GetString(challenge));

            if (dch.Rspauth == null || dch.Rspauth.Length == 0)
            {
                throw new SaslException("Expected 'rspauth' in server challenge not found");
            }

            SetComplete();
            return(new byte[0]);
        }
        //
        // Private Methods
        //

        /// <summary>
        /// Process the first challenge from the server
        /// and calculate a response
        /// </summary>
        /// <param name="challenge">The server issued challenge</param>
        /// <returns>Client response</returns>
        private byte[] OnInitialChallenge(byte[] challenge)
        {
            DigestChallenge dch =
                DigestChallenge.Parse(_encoding.GetString(challenge));

            // validate input challenge
            if (dch.Nonce == null || dch.Nonce.Length == 0)
            {
                throw new SaslException("Nonce value missing in server challenge");
            }
            if (dch.Algorithm != "md5-sess")
            {
                throw new SaslException("Invalid or missing algorithm value in server challenge");
            }


            NameCallback     nameCB  = new NameCallback(AuthorizationId);
            PasswordCallback pwdCB   = new PasswordCallback();
            RealmCallback    realmCB = new RealmCallback(dch.Realm);

            ISaslCallback[] callbacks = { nameCB, pwdCB, realmCB };
            Handler.Handle(callbacks);

            DigestResponse response = new DigestResponse();

            response.Username   = nameCB.Text;
            response.Realm      = realmCB.Text;
            response.Nonce      = dch.Nonce;
            response.Cnonce     = Cnonce;
            response.NonceCount = 1;
            response.Qop        = DigestQop.Auth; // only auth supported for now
            response.DigestUri  = Protocol.ToLower() + "/" + ServerName;
            response.MaxBuffer  = dch.MaxBuffer;
            response.Charset    = dch.Charset;
            response.Cipher     = null; // not supported for now
            response.Authzid    = AuthorizationId;
            response.AuthParam  = dch.AuthParam;

            response.Response = CalculateResponse(
                nameCB.Text, realmCB.Text, pwdCB.Text,
                dch.Nonce, response.NonceCount, response.Qop, response.DigestUri
                );

            return(_encoding.GetBytes(response.ToString()));
        }