protected override TSyncChallengeResult Challenge(
            ref SASLChallengeArguments args,
            SASLCredentialsSCRAMForClient credentials
            )
        {
            var prevState       = this._state;
            var challengeResult = SASLChallengeResult.MoreToCome;
            var writeOffset     = args.WriteOffset;

            Int32 errorCode;
            Int32 nextState;

            if (credentials == null)
            {
                errorCode = SCRAMCommon.ERROR_CLIENT_SUPPLIED_WITH_INVALID_CREDENTIALS;
                nextState = -1;
            }
            else
            {
                switch (prevState)
                {
                case STATE_INITIAL:
                    errorCode = this.PerformInitial(ref args, credentials, ref writeOffset);
                    nextState = STATE_FINAL;
                    break;

                case STATE_FINAL:
                    // Read server response and write our response
                    errorCode = this.PerformFinal(ref args, credentials, ref writeOffset);
                    nextState = STATE_VALIDATE;
                    break;

                case STATE_VALIDATE:
                    errorCode       = this.PerformValidate(ref args, credentials);
                    nextState       = STATE_COMPLETED;
                    challengeResult = SASLChallengeResult.Completed;
                    break;

                default:
                    nextState = -1;
                    errorCode = SCRAMCommon.ERROR_INVALID_STATE;
                    break;
                }
            }

            TSyncChallengeResult retVal;

            if (errorCode != 0 ||
                nextState < 0 ||
                Interlocked.CompareExchange(ref this._state, nextState, prevState) != prevState)
            {
                retVal = new TSyncChallengeResult(errorCode == 0 ? SCRAMCommon.ERROR_CONCURRENT_ACCESS : errorCode);
            }
            else
            {
                retVal = new TSyncChallengeResult((writeOffset - args.WriteOffset, challengeResult));
            }

            return(retVal);
        }
        private Int32 PerformInitial(
            ref SASLChallengeArguments args,
            SASLCredentialsSCRAMForClient credentials,
            ref Int32 writeOffset
            )
        {
            var encoding = args.Encoding;
            var array    = args.WriteArray;

            // Write "n,,n=<username>,r=<client nonce>
            // Write "n,,n="

            array.CurrentMaxCapacity = encoding.Encoding.GetByteCount(SCRAMCommon.CLIENT_FIRST_PREFIX_1 + SCRAMCommon.CLIENT_FIRST_PREFIX_2);
            encoding.WriteString(array.Array, ref writeOffset, SCRAMCommon.CLIENT_FIRST_PREFIX_1);
            var messageStart = writeOffset;

            encoding.WriteString(array.Array, ref writeOffset, SCRAMCommon.CLIENT_FIRST_PREFIX_2);

            // Write processed and escaped username
            SASLUtility.WriteString(
                credentials.Username,
                encoding,
                array,
                ref writeOffset,
                normalizer: (name, nameIdx) =>
            {
                // Escape the ',' and '=' characters, since they are reserved.
                switch (name[nameIdx])
                {
                case ',':
                    return(SCRAMCommon.COMMA_ESCAPE);

                case '=':
                    return(SCRAMCommon.EQUALS_ESCAPE);

                default:
                    return(default);
                }