forked from TalAloni/SMBLibrary
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from Dualog/update-from-origin
Update from origin
- Loading branch information
Showing
51 changed files
with
1,219 additions
and
338 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
/* Copyright (C) 2017 Tal Aloni <[email protected]>. All rights reserved. | ||
/* Copyright (C) 2017-2024 Tal Aloni <[email protected]>. All rights reserved. | ||
* | ||
* You can redistribute this program and/or modify it under the terms of | ||
* the GNU Lesser Public License as published by the Free Software Foundation, | ||
|
@@ -102,16 +102,7 @@ public override byte[] GetBytes() | |
|
||
protected virtual int GetTokenFieldsLength() | ||
{ | ||
int result = 0; | ||
if (MechanismTypeList != null) | ||
{ | ||
int typeListSequenceLength = GetMechanismTypeListSequenceLength(MechanismTypeList); | ||
int typeListSequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(typeListSequenceLength); | ||
int typeListConstructionLength = 1 + typeListSequenceLengthFieldSize + typeListSequenceLength; | ||
int typeListConstructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(typeListConstructionLength); | ||
int entryLength = 1 + typeListConstructionLengthFieldSize + 1 + typeListSequenceLengthFieldSize + typeListSequenceLength; | ||
result += entryLength; | ||
} | ||
int result = GetEncodedMechanismTypeListLength(MechanismTypeList); | ||
if (MechanismToken != null) | ||
{ | ||
int mechanismTokenLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(MechanismToken.Length); | ||
|
@@ -200,6 +191,11 @@ protected static void WriteMechanismTypeList(byte[] buffer, ref int offset, List | |
int constructionLength = 1 + sequenceLengthFieldSize + sequenceLength; | ||
ByteWriter.WriteByte(buffer, ref offset, MechanismTypeListTag); | ||
DerEncodingHelper.WriteLength(buffer, ref offset, constructionLength); | ||
WriteMechanismTypeListSequence(buffer, ref offset, mechanismTypeList, sequenceLength); | ||
} | ||
|
||
protected static void WriteMechanismTypeListSequence(byte[] buffer, ref int offset, List<byte[]> mechanismTypeList, int sequenceLength) | ||
{ | ||
ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.Sequence); | ||
DerEncodingHelper.WriteLength(buffer, ref offset, sequenceLength); | ||
foreach (byte[] mechanismType in mechanismTypeList) | ||
|
@@ -229,5 +225,32 @@ protected static void WriteMechanismListMIC(byte[] buffer, ref int offset, byte[ | |
DerEncodingHelper.WriteLength(buffer, ref offset, mechanismListMIC.Length); | ||
ByteWriter.WriteBytes(buffer, ref offset, mechanismListMIC); | ||
} | ||
|
||
public static byte[] GetMechanismTypeListBytes(List<byte[]> mechanismTypeList) | ||
{ | ||
int sequenceLength = GetMechanismTypeListSequenceLength(mechanismTypeList); | ||
int sequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(sequenceLength); | ||
int constructionLength = 1 + sequenceLengthFieldSize + sequenceLength; | ||
byte[] buffer = new byte[constructionLength]; | ||
int offset = 0; | ||
WriteMechanismTypeListSequence(buffer, ref offset, mechanismTypeList, sequenceLength); | ||
return buffer; | ||
} | ||
|
||
private static int GetEncodedMechanismTypeListLength(List<byte[]> mechanismTypeList) | ||
{ | ||
if (mechanismTypeList == null) | ||
{ | ||
return 0; | ||
} | ||
else | ||
{ | ||
int typeListSequenceLength = GetMechanismTypeListSequenceLength(mechanismTypeList); | ||
int typeListSequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(typeListSequenceLength); | ||
int typeListConstructionLength = 1 + typeListSequenceLengthFieldSize + typeListSequenceLength; | ||
int typeListConstructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(typeListConstructionLength); | ||
return 1 + typeListConstructionLengthFieldSize + 1 + typeListSequenceLengthFieldSize + typeListSequenceLength; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
/* Copyright (C) 2014-2017 Tal Aloni <[email protected]>. All rights reserved. | ||
/* Copyright (C) 2014-2024 Tal Aloni <[email protected]>. All rights reserved. | ||
* | ||
* You can redistribute this program and/or modify it under the terms of | ||
* the GNU Lesser Public License as published by the Free Software Foundation, | ||
* either version 3 of the License, or (at your option) any later version. | ||
*/ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Reflection; | ||
using System.Security.Cryptography; | ||
|
@@ -78,11 +77,26 @@ public static ICryptoTransform CreateWeakDesEncryptor(CipherMode mode, byte[] rg | |
{ | ||
DES des = DES.Create(); | ||
des.Mode = mode; | ||
DESCryptoServiceProvider sm = des as DESCryptoServiceProvider; | ||
MethodInfo mi = sm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance); | ||
object[] Par = { rgbKey, mode, rgbIV, sm.FeedbackSize, 0 }; | ||
ICryptoTransform trans = mi.Invoke(sm, Par) as ICryptoTransform; | ||
return trans; | ||
ICryptoTransform transform; | ||
if (DES.IsWeakKey(rgbKey) || DES.IsSemiWeakKey(rgbKey)) | ||
{ | ||
#if NETSTANDARD2_0 | ||
MethodInfo getTransformCoreMethodInfo = des.GetType().GetMethod("CreateTransformCore", BindingFlags.NonPublic | BindingFlags.Static); | ||
object[] getTransformCoreParameters = { mode, des.Padding, rgbKey, rgbIV, des.BlockSize / 8 , des.FeedbackSize / 8, des.BlockSize / 8, true }; | ||
transform = getTransformCoreMethodInfo.Invoke(null, getTransformCoreParameters) as ICryptoTransform; | ||
#else | ||
DESCryptoServiceProvider desServiceProvider = des as DESCryptoServiceProvider; | ||
MethodInfo newEncryptorMethodInfo = desServiceProvider.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance); | ||
object[] encryptorParameters = { rgbKey, mode, rgbIV, desServiceProvider.FeedbackSize, 0 }; | ||
transform = newEncryptorMethodInfo.Invoke(desServiceProvider, encryptorParameters) as ICryptoTransform; | ||
#endif | ||
} | ||
else | ||
{ | ||
transform = des.CreateEncryptor(rgbKey, rgbIV); | ||
} | ||
|
||
return transform; | ||
} | ||
|
||
/// <summary> | ||
|
@@ -123,7 +137,11 @@ public static byte[] DesLongEncrypt(byte[] key, byte[] plainText) | |
|
||
public static Encoding GetOEMEncoding() | ||
{ | ||
#if NETSTANDARD2_0 | ||
return ASCIIEncoding.GetEncoding(28591); | ||
#else | ||
return Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage); | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
|
@@ -239,5 +257,98 @@ public static byte[] KXKey(byte[] sessionBaseKey, NegotiateFlags negotiateFlags, | |
return keyExchangeKey; | ||
} | ||
} | ||
|
||
/// <remarks> | ||
/// Caller must verify that the authenticate message has MIC before calling this method | ||
/// </remarks> | ||
public static bool ValidateAuthenticateMessageMIC(byte[] exportedSessionKey, byte[] negotiateMessageBytes, byte[] challengeMessageBytes, byte[] authenticateMessageBytes) | ||
{ | ||
// https://msdn.microsoft.com/en-us/library/cc236695.aspx | ||
int micFieldOffset = AuthenticateMessage.GetMicFieldOffset(authenticateMessageBytes); | ||
byte[] expectedMic = ByteReader.ReadBytes(authenticateMessageBytes, micFieldOffset, AuthenticateMessage.MicFieldLenght); | ||
|
||
ByteWriter.WriteBytes(authenticateMessageBytes, micFieldOffset, new byte[AuthenticateMessage.MicFieldLenght]); | ||
byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(negotiateMessageBytes, challengeMessageBytes), authenticateMessageBytes); | ||
byte[] mic = new HMACMD5(exportedSessionKey).ComputeHash(temp); | ||
|
||
return ByteUtils.AreByteArraysEqual(mic, expectedMic); | ||
} | ||
|
||
public static byte[] ComputeClientSignKey(byte[] exportedSessionKey) | ||
{ | ||
return ComputeSignKey(exportedSessionKey, true); | ||
} | ||
|
||
public static byte[] ComputeServerSignKey(byte[] exportedSessionKey) | ||
{ | ||
return ComputeSignKey(exportedSessionKey, false); | ||
} | ||
|
||
private static byte[] ComputeSignKey(byte[] exportedSessionKey, bool isClient) | ||
{ | ||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/524cdccb-563e-4793-92b0-7bc321fce096 | ||
string str; | ||
if (isClient) | ||
{ | ||
str = "session key to client-to-server signing key magic constant"; | ||
} | ||
else | ||
{ | ||
str = "session key to server-to-client signing key magic constant"; | ||
} | ||
byte[] encodedString = Encoding.GetEncoding(28591).GetBytes(str); | ||
byte[] nullTerminatedEncodedString = ByteUtils.Concatenate(encodedString, new byte[1]); | ||
byte[] concatendated = ByteUtils.Concatenate(exportedSessionKey, nullTerminatedEncodedString); | ||
return MD5.Create().ComputeHash(concatendated); | ||
} | ||
|
||
public static byte[] ComputeClientSealKey(byte[] exportedSessionKey) | ||
{ | ||
return ComputeSealKey(exportedSessionKey, true); | ||
} | ||
|
||
public static byte[] ComputeServerSealKey(byte[] exportedSessionKey) | ||
{ | ||
return ComputeSealKey(exportedSessionKey, false); | ||
} | ||
|
||
private static byte[] ComputeSealKey(byte[] exportedSessionKey, bool isClient) | ||
{ | ||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/524cdccb-563e-4793-92b0-7bc321fce096 | ||
string str; | ||
if (isClient) | ||
{ | ||
str = "session key to client-to-server sealing key magic constant"; | ||
} | ||
else | ||
{ | ||
str = "session key to server-to-client sealing key magic constant"; | ||
} | ||
byte[] encodedString = Encoding.GetEncoding(28591).GetBytes(str); | ||
byte[] nullTerminatedEncodedString = ByteUtils.Concatenate(encodedString, new byte[1]); | ||
byte[] concatendated = ByteUtils.Concatenate(exportedSessionKey, nullTerminatedEncodedString); | ||
return MD5.Create().ComputeHash(concatendated); | ||
} | ||
|
||
public static byte[] ComputeMechListMIC(byte[] exportedSessionKey, byte[] message) | ||
{ | ||
return ComputeMechListMIC(exportedSessionKey, message, 0); | ||
} | ||
|
||
public static byte[] ComputeMechListMIC(byte[] exportedSessionKey, byte[] message, int seqNum) | ||
{ | ||
// [MS-NLMP] 3.4.4.2 | ||
byte[] signKey = ComputeClientSignKey(exportedSessionKey); | ||
byte[] sequenceNumberBytes = LittleEndianConverter.GetBytes(seqNum); | ||
byte[] concatendated = ByteUtils.Concatenate(sequenceNumberBytes, message); | ||
byte[] fullHash = new HMACMD5(signKey).ComputeHash(concatendated); | ||
byte[] hash = ByteReader.ReadBytes(fullHash, 0, 8); | ||
|
||
byte[] sealKey = ComputeClientSealKey(exportedSessionKey); | ||
byte[] encryptedHash = RC4.Encrypt(sealKey, hash); | ||
|
||
byte[] version = new byte[] { 0x01, 0x00, 0x00, 0x00 }; | ||
return ByteUtils.Concatenate(ByteUtils.Concatenate(version, encryptedHash), sequenceNumberBytes); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,11 @@ | ||
/* Copyright (C) 2014-2020 Tal Aloni <[email protected]>. All rights reserved. | ||
/* Copyright (C) 2014-2023 Tal Aloni <[email protected]>. All rights reserved. | ||
* | ||
* You can redistribute this program and/or modify it under the terms of | ||
* the GNU Lesser Public License as published by the Free Software Foundation, | ||
* either version 3 of the License, or (at your option) any later version. | ||
*/ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using System.Security.Cryptography; | ||
using Utilities; | ||
|
||
namespace SMBLibrary.Authentication.NTLM | ||
|
@@ -17,6 +16,7 @@ namespace SMBLibrary.Authentication.NTLM | |
public class AuthenticateMessage | ||
{ | ||
public const string ValidSignature = "NTLMSSP\0"; | ||
public const int MicFieldLenght = 16; | ||
|
||
public string Signature; // 8 bytes | ||
public MessageTypeName MessageType; | ||
|
@@ -59,7 +59,7 @@ public AuthenticateMessage(byte[] buffer) | |
} | ||
if (HasMicField()) | ||
{ | ||
MIC = ByteReader.ReadBytes(buffer, offset, 16); | ||
MIC = ByteReader.ReadBytes(buffer, offset, MicFieldLenght); | ||
} | ||
} | ||
|
||
|
@@ -142,5 +142,25 @@ public byte[] GetBytes() | |
|
||
return buffer; | ||
} | ||
|
||
public void CalculateMIC(byte[] sessionKey, byte[] negotiateMessage, byte[] challengeMessage) | ||
{ | ||
MIC = new byte[MicFieldLenght]; | ||
byte[] authenticateMessageBytes = GetBytes(); | ||
byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(negotiateMessage, challengeMessage), authenticateMessageBytes); | ||
MIC = new HMACMD5(sessionKey).ComputeHash(temp); | ||
} | ||
|
||
public static int GetMicFieldOffset(byte[] authenticateMessageBytes) | ||
{ | ||
NegotiateFlags negotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(authenticateMessageBytes, 60); | ||
int offset = 64; | ||
if ((negotiateFlags & NegotiateFlags.Version) > 0) | ||
{ | ||
offset += NTLMVersion.Length; | ||
} | ||
|
||
return offset; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.