/// <summary>
        /// LM v1 / NTLM v1 Extended Session Security
        /// </summary>
        private static bool AuthenticateV1Extended(string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
        {
            byte[] clientChallenge        = ByteReader.ReadBytes(lmResponse, 0, 8);
            byte[] expectedNTLMv1Response = NTLMCryptography.ComputeNTLMv1ExtendedSessionSecurityResponse(serverChallenge, clientChallenge, password);

            return(ByteUtils.AreByteArraysEqual(expectedNTLMv1Response, ntResponse));
        }
        /// <summary>
        /// LM v1 / NTLM v1
        /// </summary>
        private static bool AuthenticateV1(string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
        {
            byte[] expectedLMResponse = NTLMCryptography.ComputeLMv1Response(serverChallenge, password);
            if (ByteUtils.AreByteArraysEqual(expectedLMResponse, lmResponse))
            {
                return(true);
            }

            byte[] expectedNTResponse = NTLMCryptography.ComputeNTLMv1Response(serverChallenge, password);
            return(ByteUtils.AreByteArraysEqual(expectedNTResponse, ntResponse));
        }
        /// <summary>
        /// LM v2 / NTLM v2
        /// </summary>
        private bool AuthenticateV2(string domainName, string accountName, string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
        {
            // Note: Linux CIFS VFS 3.10 will send LmChallengeResponse with length of 0 bytes
            if (lmResponse.Length == 24)
            {
                byte[] _LMv2ClientChallenge = ByteReader.ReadBytes(lmResponse, 16, 8);
                byte[] expectedLMv2Response = NTLMCryptography.ComputeLMv2Response(serverChallenge, _LMv2ClientChallenge, password, accountName, domainName);
                if (ByteUtils.AreByteArraysEqual(expectedLMv2Response, lmResponse))
                {
                    return(true);
                }
            }

            if (AuthenticationMessageUtils.IsNTLMv2NTResponse(ntResponse))
            {
                byte[] clientNTProof = ByteReader.ReadBytes(ntResponse, 0, 16);
                byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(ntResponse, 16, ntResponse.Length - 16);
                byte[] expectedNTProof = NTLMCryptography.ComputeNTLMv2Proof(serverChallenge, clientChallengeStructurePadded, password, accountName, domainName);

                return(ByteUtils.AreByteArraysEqual(clientNTProof, expectedNTProof));
            }
            return(false);
        }
        public override NTStatus Authenticate(object context, AuthenticateMessage message)
        {
            AuthContext authContext = context as AuthContext;

            if (authContext == null)
            {
                // There are two possible reasons for authContext to be null:
                // 1. We have a bug in our implementation, let's assume that's not the case,
                //    according to [MS-SMB2] 3.3.5.5.1 we aren't allowed to return SEC_E_INVALID_HANDLE anyway.
                // 2. The client sent AuthenticateMessage without sending NegotiateMessage first,
                //    in this case the correct response is SEC_E_INVALID_TOKEN.
                return(NTStatus.SEC_E_INVALID_TOKEN);
            }

            authContext.DomainName  = message.DomainName;
            authContext.UserName    = message.UserName;
            authContext.WorkStation = message.WorkStation;
            if (message.Version != null)
            {
                authContext.OSVersion = message.Version.ToString();
            }

            if ((message.NegotiateFlags & NegotiateFlags.Anonymous) > 0)
            {
                if (this.EnableGuestLogin)
                {
                    authContext.IsGuest = true;
                    return(NTStatus.STATUS_SUCCESS);
                }
                else
                {
                    return(NTStatus.STATUS_LOGON_FAILURE);
                }
            }

            if (!m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower()))
            {
                return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT);
            }

            string password = m_GetUserPassword(message.UserName);

            if (password == null)
            {
                if (this.EnableGuestLogin)
                {
                    authContext.IsGuest = true;
                    return(NTStatus.STATUS_SUCCESS);
                }
                else
                {
                    if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true))
                    {
                        return(NTStatus.STATUS_LOGON_FAILURE);
                    }
                    else
                    {
                        return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT);
                    }
                }
            }

            bool success;

            byte[] serverChallenge = authContext.ServerChallenge;
            byte[] sessionBaseKey;
            byte[] keyExchangeKey = null;
            if ((message.NegotiateFlags & NegotiateFlags.ExtendedSessionSecurity) > 0)
            {
                if (AuthenticationMessageUtils.IsNTLMv1ExtendedSessionSecurity(message.LmChallengeResponse))
                {
                    // NTLM v1 Extended Session Security:
                    success = AuthenticateV1Extended(password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
                    if (success)
                    {
                        // https://msdn.microsoft.com/en-us/library/cc236699.aspx
                        sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password));
                        byte[] lmowf = NTLMCryptography.LMOWFv1(password);
                        keyExchangeKey = NTLMCryptography.KXKey(sessionBaseKey, message.NegotiateFlags, message.LmChallengeResponse, serverChallenge, lmowf);
                    }
                }
                else
                {
                    // NTLM v2:
                    success = AuthenticateV2(message.DomainName, message.UserName, password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
                    if (success)
                    {
                        // https://msdn.microsoft.com/en-us/library/cc236700.aspx
                        byte[] responseKeyNT = NTLMCryptography.NTOWFv2(password, message.UserName, message.DomainName);
                        byte[] ntProofStr    = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16);
                        sessionBaseKey = new HMACMD5(responseKeyNT).ComputeHash(ntProofStr);
                        keyExchangeKey = sessionBaseKey;
                    }
                }
            }
            else
            {
                success = AuthenticateV1(password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
                if (success)
                {
                    // https://msdn.microsoft.com/en-us/library/cc236699.aspx
                    sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password));
                    byte[] lmowf = NTLMCryptography.LMOWFv1(password);
                    keyExchangeKey = NTLMCryptography.KXKey(sessionBaseKey, message.NegotiateFlags, message.LmChallengeResponse, serverChallenge, lmowf);
                }
            }

            if (success)
            {
                // https://msdn.microsoft.com/en-us/library/cc236676.aspx
                // https://blogs.msdn.microsoft.com/openspecification/2010/04/19/ntlm-keys-and-sundry-stuff/
                if ((message.NegotiateFlags & NegotiateFlags.KeyExchange) > 0)
                {
                    authContext.SessionKey = RC4.Decrypt(keyExchangeKey, message.EncryptedRandomSessionKey);
                }
                else
                {
                    authContext.SessionKey = keyExchangeKey;
                }
                return(NTStatus.STATUS_SUCCESS);
            }
            else
            {
                if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true))
                {
                    return(NTStatus.STATUS_LOGON_FAILURE);
                }
                else
                {
                    return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT);
                }
            }
        }