// Section 3.3.2 // // Set LmChallengeResponse to ConcatenationOf( // HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)), // ClientChallenge ) private int makeLm2ChallengeResponse(byte[] lm2Hash, ReadOnlySpan <byte> serverChallenge, Span <byte> clientChallenge, ref Span <byte> responseAsBytes) { Debug.Assert(serverChallenge.Length == ChallengeLength); Debug.Assert(clientChallenge.Length == ChallengeLength); Debug.Assert(lm2Hash.Length == DigestLength); Span <AuthenticateMessage> response = MemoryMarshal.Cast <byte, AuthenticateMessage>(responseAsBytes); // Get server and client nonce Span <byte> blob = stackalloc byte[16]; serverChallenge.CopyTo(blob); clientChallenge.CopyTo(blob.Slice(ChallengeLength)); Span <byte> lmResponse = responseAsBytes.Slice((int)Marshal.OffsetOf(typeof(AuthenticateMessage), "LmResponse"), ChallengeResponseLength); HMACMD5 hmac = new HMACMD5(lm2Hash); bool result = hmac.TryComputeHash(blob, lmResponse, out int bytes); if (!result || bytes != DigestLength) { return(0); } clientChallenge.CopyTo(lmResponse.Slice(DigestLength)); SetField(ref response[0].LmChallengeResponse, ChallengeResponseLength, (int)Marshal.OffsetOf(typeof(AuthenticateMessage), "LmResponse")); return(ChallengeResponseLength); }
// Section 3.3.2 // // Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), Time, ClientChallenge, Z(4), ServerName, Z(4)) // Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, temp)) // Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp) private unsafe int makeNtlm2ChallengeResponse(byte[] lm2Hash, ReadOnlySpan <byte> serverChallenge, Span <byte> clientChallenge, ReadOnlySpan <byte> serverInfo, ref MessageField field, ref Span <byte> payload) { Debug.Assert(serverChallenge.Length == ChallengeLength); Debug.Assert(clientChallenge.Length == ChallengeLength); Debug.Assert(lm2Hash.Length == DigestLength); Span <byte> blob = payload.Slice(0, sizeof(NtChallengeResponse) + serverInfo.Length); Span <NtChallengeResponse> temp = MemoryMarshal.Cast <byte, NtChallengeResponse>(blob.Slice(0, sizeof(NtChallengeResponse))); temp[0].HiResponserversion = 1; temp[0].Responserversion = 1; temp[0].Time = DateTime.Now.Ticks; int offset = (int)Marshal.OffsetOf(typeof(NtChallengeResponse), "ClientChallenge"); clientChallenge.CopyTo(blob.Slice(offset, ChallengeLength)); offset += ChallengeLength + 4; // challengeLength + Z4 serverInfo.CopyTo(blob.Slice(offset)); // We will prepend server chalenge for purpose of calculating NTProofStr // It will be overriten later. serverChallenge.CopyTo(blob.Slice(ChallengeLength, ChallengeLength)); Span <byte> NTProofStr = stackalloc byte[DigestLength]; HMACMD5 hmac = new HMACMD5(lm2Hash); bool result = hmac.TryComputeHash(blob.Slice(ChallengeLength), NTProofStr, out int bytes); if (!result || bytes != DigestLength) { return(0); } // we created temp part in place where it needs to be. // now we need to prepend it with calculated hmac. // Write first 16 bytes, overiding challengeLength part. NTProofStr.CopyTo(blob); SetField(ref field, blob.Length, sizeof(AuthenticateMessage)); payload = payload.Slice(blob.Length); return(blob.Length); }