static byte[] ComputeNtlmV2(Type2Message type2, string username, string password, string domain) { var ntlm_hash = ComputeNtlmPassword(password); var ubytes = Encoding.Unicode.GetBytes(username.ToUpperInvariant()); var tbytes = Encoding.Unicode.GetBytes(domain); var bytes = new byte[ubytes.Length + tbytes.Length]; ubytes.CopyTo(bytes, 0); Array.Copy(tbytes, 0, bytes, ubytes.Length, tbytes.Length); byte[] ntlm_v2_hash; using (var md5 = new HMACMD5(ntlm_hash)) ntlm_v2_hash = md5.ComputeHash(bytes); Array.Clear(ntlm_hash, 0, ntlm_hash.Length); using (var md5 = new HMACMD5(ntlm_v2_hash)) { var now = DateTime.Now; var timestamp = now.Ticks - 504911232000000000; var nonce = new byte[8]; using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(nonce); var targetInfo = type2.EncodedTargetInfo; var blob = new byte[28 + targetInfo.Length]; blob[0] = 0x01; blob[1] = 0x01; Buffer.BlockCopy(BitConverterLE.GetBytes(timestamp), 0, blob, 8, 8); Buffer.BlockCopy(nonce, 0, blob, 16, 8); Buffer.BlockCopy(targetInfo, 0, blob, 28, targetInfo.Length); var challenge = type2.Nonce; var hashInput = new byte[challenge.Length + blob.Length]; challenge.CopyTo(hashInput, 0); blob.CopyTo(hashInput, challenge.Length); var blobHash = md5.ComputeHash(hashInput); var response = new byte[blob.Length + blobHash.Length]; blobHash.CopyTo(response, 0); blob.CopyTo(response, blobHash.Length); Array.Clear(ntlm_v2_hash, 0, ntlm_v2_hash.Length); Array.Clear(hashInput, 0, hashInput.Length); Array.Clear(blobHash, 0, blobHash.Length); Array.Clear(nonce, 0, nonce.Length); Array.Clear(blob, 0, blob.Length); return(response); } }
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); }