/// <summary>
        /// Requests that the provided stream be authenticated 
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="additionalChallenge">Additional data to include in the challenge. If using SSL certificates, 
        /// adding the thumbprint to the challenge will allow detecting man in the middle attacks.</param>
        /// <returns></returns>
        public ScramServerSession AuthenticateAsServer(Stream stream, byte[] additionalChallenge = null)
        {
            if (additionalChallenge == null)
                additionalChallenge = new byte[] { };

            byte[] usernameBytes = stream.ReadBytes();
            byte[] clientNonce = stream.ReadBytes();

            ScramUserCredential user;
            if (!Users.TryLookup(usernameBytes, out user))
                return null;

            byte[] serverNonce = m_nonce.Next();
            stream.WriteByte((byte)user.HashMethod);
            stream.WriteWithLength(serverNonce);
            stream.WriteWithLength(user.Salt);
            stream.Write(user.Iterations);
            stream.Flush();

            byte[] authMessage = Scram.ComputeAuthMessage(serverNonce, clientNonce, user.Salt, usernameBytes, user.Iterations, additionalChallenge);
            byte[] clientSignature = user.ComputeClientSignature(authMessage);
            byte[] serverSignature = user.ComputeServerSignature(authMessage);
            byte[] clientProof = stream.ReadBytes();

            byte[] clientKeyVerify = Scram.XOR(clientProof, clientSignature);
            byte[] storedKeyVerify = user.ComputeStoredKey(clientKeyVerify);

            if (storedKeyVerify.SecureEquals(user.StoredKey))
            {
                //Client holds the password
                //Send ServerSignature
                stream.WriteWithLength(serverSignature);
                stream.Flush();
                return new ScramServerSession(user.UserName);
            }
            return null;
        }
        public bool AuthenticateAsClient(Stream stream, byte[] additionalChallenge = null)
        {
            if (additionalChallenge == null)
                additionalChallenge = new byte[] { };

            byte[] clientNonce = m_nonce.Next();
            stream.WriteWithLength(m_usernameBytes);
            stream.WriteWithLength(clientNonce);
            stream.Flush();

            HashMethod hashMethod = (HashMethod)stream.ReadByte();
            byte[] serverNonce = stream.ReadBytes();
            byte[] salt = stream.ReadBytes();
            int iterations = stream.ReadInt32();

            SetServerValues(hashMethod, salt, iterations);

            byte[] authMessage = Scram.ComputeAuthMessage(serverNonce, clientNonce, salt, m_usernameBytes, iterations, additionalChallenge);
            byte[] clientSignature = ComputeClientSignature(authMessage);
            byte[] clientProof = Scram.XOR(m_clientKey, clientSignature);
            stream.WriteWithLength(clientProof);
            stream.Flush();

            byte[] serverSignature = ComputeServerSignature(authMessage);
            byte[] serverSignatureVerify = stream.ReadBytes();
            return (serverSignature.SecureEquals(serverSignatureVerify));
        }