Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,25 @@ private enum AvId
}

[StructLayout(LayoutKind.Sequential)]
private unsafe struct MessageField
private struct MessageField
{
public ushort Length;
public ushort MaximumLength;
private ushort _length;
private ushort _maximumLength;
private int _payloadOffset;
public ushort Length
{
readonly get => BitConverter.IsLittleEndian ? _length : BinaryPrimitives.ReverseEndianness(_length);
set => _length = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value);
}
public ushort MaximumLength
{
readonly get => BitConverter.IsLittleEndian ? _maximumLength : BinaryPrimitives.ReverseEndianness(_maximumLength);
set => _maximumLength = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value);
}
public int PayloadOffset
{
readonly get =>BitConverter.IsLittleEndian? _payloadOffset: BinaryPrimitives.ReverseEndianness(_payloadOffset);
set =>_payloadOffset = BitConverter.IsLittleEndian? value: BinaryPrimitives.ReverseEndianness(value);
readonly get => BitConverter.IsLittleEndian ? _payloadOffset : BinaryPrimitives.ReverseEndianness(_payloadOffset);
set => _payloadOffset = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value);
}
}

Expand All @@ -158,8 +168,8 @@ private unsafe struct Version
public byte CurrentRevision;
public ushort ProductBuild
{
readonly get =>BitConverter.IsLittleEndian? _productBuild: BinaryPrimitives.ReverseEndianness(_productBuild);
set =>_productBuild = BitConverter.IsLittleEndian? value: BinaryPrimitives.ReverseEndianness(value);
readonly get => BitConverter.IsLittleEndian ? _productBuild : BinaryPrimitives.ReverseEndianness(_productBuild);
set => _productBuild = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value);
}
}

Expand All @@ -174,8 +184,8 @@ private unsafe struct NegotiateMessage
public Version Version;
public Flags Flags
{
readonly get =>BitConverter.IsLittleEndian? _flags: (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags);
set =>_flags = BitConverter.IsLittleEndian? value: (Flags)BinaryPrimitives.ReverseEndianness((uint)value);
readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags);
set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value);
}
}

Expand All @@ -185,11 +195,16 @@ private unsafe struct ChallengeMessage
{
public MessageHeader Header;
public MessageField TargetName;
public Flags Flags;
private Flags _flags;
public fixed byte ServerChallenge[ChallengeLength];
private ulong _unused;
public MessageField TargetInfo;
public Version Version;
public Flags Flags
{
readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags);
set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value);
}
}

// TYPE 3 message
Expand All @@ -203,9 +218,14 @@ private unsafe struct AuthenticateMessage
public MessageField UserName;
public MessageField Workstation;
public MessageField EncryptedRandomSessionKey;
public Flags Flags;
private Flags _flags;
public Version Version;
public fixed byte Mic[16];
public Flags Flags
{
readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags);
set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value);
}
}

// Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), Time, ClientChallenge, Z(4), ServerName, Z(4))
Expand All @@ -218,10 +238,15 @@ private unsafe struct NtChallengeResponse
private byte _reserved1;
private byte _reserved2;
private int _reserved3;
public long Time;
private long _time;
public fixed byte ClientChallenge[ChallengeLength];
private int _reserved4;
public fixed byte ServerInfo[4]; // Has to be non-zero size, so set it to the Z(4) padding
public long Time
{
readonly get => BitConverter.IsLittleEndian ? _time : BinaryPrimitives.ReverseEndianness(_time);
set => _time = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value);
}
}

public override bool IsAuthenticated => _isAuthenticated;
Expand Down Expand Up @@ -321,42 +346,29 @@ private static unsafe void CreateNtlmNegotiateMessage(Span<byte> asBytes, Flags
message.Version = s_version;
}

private static unsafe int GetFieldLength(MessageField field)
{
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(&field, sizeof(MessageField));
return BinaryPrimitives.ReadInt16LittleEndian(span);
}

private static unsafe int GetFieldOffset(MessageField field)
{
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(&field, sizeof(MessageField));
return BinaryPrimitives.ReadInt16LittleEndian(span.Slice(4));
}

private static ReadOnlySpan<byte> GetField(MessageField field, ReadOnlySpan<byte> payload)
{
int offset = GetFieldOffset(field);
int length = GetFieldLength(field);
int offset = field.PayloadOffset;
int length = field.Length;

if (length == 0 || offset + length > payload.Length)
{
return ReadOnlySpan<byte>.Empty;
}

return payload.Slice(GetFieldOffset(field), GetFieldLength(field));
return payload.Slice(offset, length);
}

private static unsafe void SetField(ref MessageField field, int length, int offset)
private static void SetField(ref MessageField field, int length, int offset)
{
if (length is < 0 or > short.MaxValue)
{
throw new Win32Exception(NTE_FAIL);
}

Span<byte> span = MemoryMarshal.AsBytes(new Span<MessageField>(ref field));
BinaryPrimitives.WriteInt16LittleEndian(span, (short)length);
BinaryPrimitives.WriteInt16LittleEndian(span.Slice(2), (short)length);
BinaryPrimitives.WriteInt32LittleEndian(span.Slice(4), offset);
field.Length = (ushort)length;
field.MaximumLength = (ushort)length;
field.PayloadOffset = offset;
}

private static void AddToPayload(ref MessageField field, ReadOnlySpan<byte> data, Span<byte> payload, ref int offset)
Expand Down Expand Up @@ -589,7 +601,7 @@ private static byte[] DeriveKey(ReadOnlySpan<byte> exportedSessionKey, ReadOnlyS
return null;
}

Flags flags = BitConverter.IsLittleEndian ? challengeMessage.Flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)challengeMessage.Flags);
Flags flags = challengeMessage.Flags;
ReadOnlySpan<byte> targetName = GetField(challengeMessage.TargetName, blob);

// Only NTLMv2 with MIC is supported
Expand Down
Loading