def get_ntlm_response(self, flags, challenge, target_info=None, channel_binding=None):
        """
        Computes the 24 byte NTLM challenge response given the 8 byte server challenge, along with the session key.
        If NTLMv2 is used, the TargetInfo structure must be supplied, the updated TargetInfo structure will be returned
        :param challenge: The 8-byte challenge message generated by the server
        :return: A tuple containing the 24 byte NTLM Hash, Session Key and TargetInfo
        """
        # TODO: IMPLEMENT THE FOLLOWING FEATURES
        # If NTLM v2 authentication is used and the CHALLENGE_MESSAGE does not contain both MsvAvNbComputerName and
        # MsvAvNbDomainName AVPairs and either Integrity is TRUE or Confidentiality is TRUE, then return STATUS_LOGON_FAILURE.

        # If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field, the client SHOULD NOT send
        # the LmChallengeResponse and SHOULD set the LmChallengeResponseLen and LmChallengeResponseMaxLen fields in the
        # AUTHENTICATE_MESSAGE to zero.

        # If lm compatibility level is 3 or lower, but the server negotiated NTLM2, generate an
        # NTLM2 response in preference to the weaker NTLMv1.
        if flags & NegotiateFlag.NTLMSSP_NTLM2_KEY and self._lm_compatibility < 3:
            response, key = PasswordAuthentication.get_ntlm2_response(self._password, challenge, self._client_challenge)

        elif 0 <= self._lm_compatibility < 3:
            response, key = PasswordAuthentication.get_ntlmv1_response(self._password, challenge)
        else:
            # We should use the timestamp included in TargetInfo, if no timestamp is set we generate one and add it to
            # the outgoing TargetInfo. If the timestamp is set, we should also set the MIC flag
            if target_info is None:
                target_info = TargetInfo()
            if target_info[TargetInfo.NTLMSSP_AV_TIME] is None:
                timestamp = PasswordAuthentication._get_ntlm_timestamp()
            else:
                # TODO: If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
                # TODO: the client SHOULD provide a MIC.
                timestamp = target_info[TargetInfo.NTLMSSP_AV_TIME][1]

            #target_info[TargetInfo.NTLMSSP_AV_FLAGS] = struct.pack('<I', 2)
            # Calculating channel bindings is poorly documented. It is implemented in winrmlib, and needs to be
            # moved here
            # if self._av_channel_bindings is True and channel_binding is not None:
            #     target_info[TargetInfo.NTLMSSP_AV_CHANNEL_BINDINGS] = channel_binding

            response, key, target_info = PasswordAuthentication.get_ntlmv2_response(
                self._domain, self._username, self._password.encode('utf-16le'), challenge,
                self._client_challenge, timestamp, target_info)

        return response, key, target_info
Computes the 24 byte NTLM challenge response given the 8 byte server challenge, along with the session key.
        If NTLMv2 is used, the TargetInfo structure must be supplied, the updated TargetInfo structure will be returned
        :param challenge: The 8-byte challenge message generated by the server
        :return: A tuple containing the 24 byte NTLM Hash, Session Key and TargetInfo