public static DigestChallenge Parse(string challenge)
        {
            DigestChallenge  parsed = new DigestChallenge();
            StringDictionary parts  = ParseParameters(challenge);

            foreach (string optname in parts.Keys)
            {
                switch (optname)
                {
                case "realm":
                    parsed._realm = parts[optname];
                    break;

                case "nonce":
                    parsed._nonce = parts[optname];
                    break;

                case "qop-options":
                    parsed._qopOptions = GetOptions(parts[optname]);
                    break;

                case "cipher-opts":
                    parsed._cipherOptions = GetOptions(parts[optname]);
                    break;

                case "stale":
                    parsed._stale = Convert.ToBoolean(parts[optname], CultureInfo.InvariantCulture);
                    break;

                case "maxbuf":
                    parsed._maxBuffer = Convert.ToInt32(parts[optname], CultureInfo.InvariantCulture);
                    break;

                case "charset":
                    parsed._charset = parts[optname];
                    break;

                case "algorithm":
                    parsed._algorithm = parts[optname];
                    break;

                case "auth-param":
                    parsed._authParam = parts[optname];
                    break;

                case "rspauth":
                    parsed._rspauth = parts[optname];
                    break;
                }
            }

            return(parsed);
        }
        /// <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()));
        }
      public static DigestChallenge Parse(string challenge)
      {
         DigestChallenge parsed = new DigestChallenge();
         StringDictionary parts = ParseParameters(challenge);
         foreach ( string optname in parts.Keys )
         {
            switch ( optname )
            {
            case "realm":
               parsed._realm = parts[optname];
               break;
            case "nonce":
               parsed._nonce = parts[optname];
               break;
            case "qop-options":
               parsed._qopOptions = GetOptions(parts[optname]);
               break;
            case "cipher-opts":
               parsed._cipherOptions = GetOptions(parts[optname]);
               break;
            case "stale":
               parsed._stale = Convert.ToBoolean(parts[optname], CultureInfo.InvariantCulture);
               break;
            case "maxbuf":
               parsed._maxBuffer = Convert.ToInt32(parts[optname], CultureInfo.InvariantCulture);
               break;
            case "charset":
               parsed._charset = parts[optname];
               break;
            case "algorithm":
               parsed._algorithm = parts[optname];
               break;
            case "auth-param":
               parsed._authParam = parts[optname];
               break;
            case "rspauth":
               parsed._rspauth = parts[optname];
               break;
            }
         }

         return parsed;
      }