public static void ComputeNtlmV2(NtlmChallengeMessage type2, string domain, string userName, string password, byte[] targetInfo, byte[] clientChallenge, long?time, out byte[] ntChallengeResponse, out byte[] lmChallengeResponse, out byte[] sessionBaseKey) { if (userName.Length == 0 && password.Length == 0) { // Special case for anonymous authentication ntChallengeResponse = null; lmChallengeResponse = Z1; sessionBaseKey = null; return; } var timestamp = (time ?? DateTime.UtcNow.Ticks) - 504911232000000000; var responseKey = NTOWFv2(domain, userName, password); // Note: If NTLM v2 authentication is used, the client SHOULD send the timestamp in the CHALLENGE_MESSAGE. if (type2.TargetInfo?.Timestamp != null) { timestamp = type2.TargetInfo.Timestamp.Value; } var temp = ConcatenationOf(Responserversion, HiResponserversion, Z6, BitConverterLE.GetBytes(timestamp), clientChallenge, Z4, targetInfo, Z4); var proof = HMACMD5(responseKey, type2.ServerChallenge, temp); sessionBaseKey = HMACMD5(responseKey, proof); ntChallengeResponse = ConcatenationOf(proof, temp); Array.Clear(proof, 0, proof.Length); Array.Clear(temp, 0, temp.Length); var hash = HMACMD5(responseKey, type2.ServerChallenge, clientChallenge); Array.Clear(responseKey, 0, responseKey.Length); // Note: If NTLM v2 authentication is used and the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an // MsvAvTimestamp present, the client SHOULD NOT send the LmChallengeResponse and SHOULD send Z(24) instead. if (type2.TargetInfo?.Timestamp == null) { lmChallengeResponse = ConcatenationOf(hash, clientChallenge); } else { lmChallengeResponse = Z24; } Array.Clear(hash, 0, hash.Length); }
public NtlmAuthenticateMessage(NtlmNegotiateMessage negotiate, NtlmChallengeMessage challenge, string userName, string password, string domain, string workstation) : base(3) { if (negotiate == null) { throw new ArgumentNullException(nameof(negotiate)); } if (challenge == null) { throw new ArgumentNullException(nameof(challenge)); } if (userName == null) { throw new ArgumentNullException(nameof(userName)); } if (password == null) { throw new ArgumentNullException(nameof(password)); } clientChallenge = NtlmUtils.NONCE(8); this.negotiate = negotiate; this.challenge = challenge; if (!string.IsNullOrEmpty(domain)) { Domain = domain; } else if ((challenge.Flags & NtlmFlags.TargetTypeDomain) != 0) { // The server is domain-joined, so the TargetName will be the domain. Domain = challenge.TargetName; } else if (challenge.TargetInfo != null) { // The server is not domain-joined, so the TargetName will be the machine name of the server. Domain = challenge.TargetInfo.DomainName; } Workstation = workstation; UserName = userName; Password = password; // Use only the features supported by both the client and server. Flags = negotiate.Flags & challenge.Flags; // If the client and server both support NEGOTIATE_UNICODE, disable NEGOTIATE_OEM. if ((Flags & NtlmFlags.NegotiateUnicode) != 0) { Flags &= ~NtlmFlags.NegotiateOem; } // TODO: throw if Unicode && Oem are both unset? // If the client and server both support NEGOTIATE_EXTENDED_SESSIONSECURITY, disable NEGOTIATE_LM_KEY. if ((Flags & NtlmFlags.NegotiateExtendedSessionSecurity) != 0) { Flags &= ~NtlmFlags.NegotiateLanManagerKey; } // Disable NEGOTIATE_KEY_EXCHANGE if neither NEGOTIATE_SIGN nor NEGOTIATE_SEAL are also present. if ((Flags & NtlmFlags.NegotiateKeyExchange) != 0 && (Flags & (NtlmFlags.NegotiateSign | NtlmFlags.NegotiateSeal)) == 0) { Flags &= ~NtlmFlags.NegotiateKeyExchange; } // If we had RequestTarget in our initial NEGOTIATE_MESSAGE, include it again in this message(?) if ((negotiate.Flags & NtlmFlags.RequestTarget) != 0) { Flags |= NtlmFlags.RequestTarget; } // If NEGOTIATE_VERSION is set, grab the OSVersion from our original negotiate message. if ((Flags & NtlmFlags.NegotiateVersion) != 0) { OSVersion = negotiate.OSVersion ?? OSVersion; } }
public NtlmAuthenticateMessage(byte[] message, int startIndex, int length) : base(3) { Decode(message, startIndex, length); challenge = null; }