/// <summary> /// Creates the NTLM negotiate (Type 1) message. /// </summary> protected override void BuildMessage() { int initialLength = SignatureLength + MessageTypeLength + FlagsLength + SecurityBufferLength * 2 + VersionLength; int domainBytesLength = 0; if (domainBytes != null) { domainBytesLength = domainBytes.Length; } int hostBytesLength = 0; if (hostBytes != null) { hostBytesLength = hostBytes.Length; } // Now, build the message. Calculate its length first, including // signature or type. int finalLength = initialLength + hostBytesLength + domainBytesLength; // Set up the response. This will initialize the signature, message // type, and flags. InitializeMessage(finalLength, NtlmMessageType.Negotiate); // Flags. These are the complete set of flags we support. AddUInt((uint)flags); // Domain length (two times). AddUShort(domainBytesLength); AddUShort(domainBytesLength); // Domain offset. AddUInt(Convert.ToUInt32(hostBytesLength + initialLength)); // Host length (two times). AddUShort(hostBytesLength); AddUShort(hostBytesLength); // Host offset (always 32 + 8). AddUInt(Convert.ToUInt32(initialLength)); // Add version (for debugging purposes) NtlmVersion version = new NtlmVersion(5, 1, 2600); AddBytes(version.AsBytes()); // Host (workstation) String. if (hostBytes != null) { AddBytes(hostBytes); } // Domain String. if (domainBytes != null) { AddBytes(domainBytes); } }
/// <summary> /// Creates the NTLM authenticate (Type 3) message. /// </summary> protected override void BuildMessage() { int ntlmResponseLength = ntlmResponse.Length; int lmResponseLength = lmResponse.Length; int domainLength = domainBytes != null ? domainBytes.Length : 0; int hostLength = hostBytes != null ? hostBytes.Length : 0; int userLength = userBytes.Length; int sessionKeyLength; if (sessionKey != null) { sessionKeyLength = sessionKey.Length; } else { sessionKeyLength = 0; } // Calculate the layout within the packet int lmResponseOffset = 72; if (isMessageIntegrityCodeRequired) { lmResponseOffset += 16; } int ntlmResponseOffset = lmResponseOffset + lmResponseLength; int domainOffset = ntlmResponseOffset + ntlmResponseLength; int userOffset = domainOffset + domainLength; int hostOffset = userOffset + userLength; int sessionKeyOffset = hostOffset + hostLength; int finalLength = sessionKeyOffset + sessionKeyLength; // Start the response. Length includes signature and type InitializeMessage(finalLength, NtlmMessageType.Authenticate); // LM Resp Length (twice) AddUShort(lmResponseLength); AddUShort(lmResponseLength); // LM Resp Offset AddUInt(Convert.ToUInt32(lmResponseOffset)); // NT Resp Length (twice) AddUShort(ntlmResponseLength); AddUShort(ntlmResponseLength); // NT Resp Offset AddUInt(Convert.ToUInt32(ntlmResponseOffset)); // Domain length (twice) AddUShort(domainLength); AddUShort(domainLength); // Domain offset. AddUInt(Convert.ToUInt32(domainOffset)); // User Length (twice) AddUShort(userLength); AddUShort(userLength); // User offset AddUInt(Convert.ToUInt32(userOffset)); // Host length (twice) AddUShort(hostLength); AddUShort(hostLength); // Host offset AddUInt(Convert.ToUInt32(hostOffset)); // Session key length (twice) AddUShort(sessionKeyLength); AddUShort(sessionKeyLength); // Session key offset AddUInt(Convert.ToUInt32(sessionKeyOffset)); // Flags. AddUInt((uint)negotiatedOptionFlags); // OS version values (only used for debugging purposes, // so we are hard-coding 5.1.2600, or Windows XP). A // future version should likely query the actual OS. NtlmVersion version = new NtlmVersion(5, 1, 2600); AddBytes(version.AsBytes()); int micPosition = -1; if (isMessageIntegrityCodeRequired) { micPosition = CurrentOutputPosition; CurrentOutputPosition += 16; } // Add the actual data AddBytes(lmResponse); AddBytes(ntlmResponse); AddBytes(domainBytes); AddBytes(userBytes); AddBytes(hostBytes); if (sessionKey != null) { AddBytes(sessionKey); } // Write the mic back into its slot in the message if (isMessageIntegrityCodeRequired) { // Computation of message integrity code (MIC) as specified // in [MS-NLMP] section 3.2.5.1.2. List <byte> data = new List <byte>(); data.AddRange(type1Message); data.AddRange(type2Message); data.AddRange(MessageContents); byte[] mic; using (HMACMD5 hmac = new HMACMD5(exportedSessionKey)) { mic = hmac.ComputeHash(data.ToArray()); } Array.Copy(mic, 0, MessageContents, micPosition, mic.Length); } }