From 40d7aaa228c1483ff82bc1f4977a1acc0e6977c1 Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Wed, 5 Jun 2019 15:56:04 +0300 Subject: [PATCH] SMBLibrary: Moved tests to separate project --- ...lStudio.QualityTools.UnitTestFramework.dll | Bin 0 -> 77824 bytes .../NTLM/NTLMAuthenticationTests.cs | 168 ++++++++++++ SMBLibrary.Tests/NTLM/NTLMSigningTests.cs | 240 ++++++++++++++++++ SMBLibrary.Tests/NTLM/RC4Tests.cs | 136 ++++++++++ SMBLibrary.Tests/NetBiosTests.cs | 44 ++++ SMBLibrary.Tests/Program.cs | 20 ++ SMBLibrary.Tests/Properties/AssemblyInfo.cs | 33 +++ SMBLibrary.Tests/RPCTests.cs | 110 ++++++++ SMBLibrary.Tests/SMB2SigningTests.cs | 62 +++++ SMBLibrary.Tests/SMBLibrary.Tests.csproj | 69 +++++ SMBLibrary/Authentication/NTLM/Helpers/MD4.cs | 2 +- SMBLibrary/SMBLibrary.csproj | 6 - SMBServer.sln | 6 + 13 files changed, 889 insertions(+), 7 deletions(-) create mode 100644 SMBLibrary.Tests/Components/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll create mode 100644 SMBLibrary.Tests/NTLM/NTLMAuthenticationTests.cs create mode 100644 SMBLibrary.Tests/NTLM/NTLMSigningTests.cs create mode 100644 SMBLibrary.Tests/NTLM/RC4Tests.cs create mode 100644 SMBLibrary.Tests/NetBiosTests.cs create mode 100644 SMBLibrary.Tests/Program.cs create mode 100644 SMBLibrary.Tests/Properties/AssemblyInfo.cs create mode 100644 SMBLibrary.Tests/RPCTests.cs create mode 100644 SMBLibrary.Tests/SMB2SigningTests.cs create mode 100644 SMBLibrary.Tests/SMBLibrary.Tests.csproj diff --git a/SMBLibrary.Tests/Components/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll b/SMBLibrary.Tests/Components/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll new file mode 100644 index 0000000000000000000000000000000000000000..387ad78fabddc1de49a8af3223708f5af9fc241e GIT binary patch literal 77824 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 E2Js>;y8r+H literal 0 HcmV?d00001 diff --git a/SMBLibrary.Tests/NTLM/NTLMAuthenticationTests.cs b/SMBLibrary.Tests/NTLM/NTLMAuthenticationTests.cs new file mode 100644 index 0000000..224da07 --- /dev/null +++ b/SMBLibrary.Tests/NTLM/NTLMAuthenticationTests.cs @@ -0,0 +1,168 @@ +/* Copyright (C) 2014-2019 Tal Aloni . 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 Microsoft.VisualStudio.TestTools.UnitTesting; +using SMBLibrary.Authentication.NTLM; +using Utilities; + +namespace SMBLibrary.Tests +{ + /// + /// [MS-NLMP] Tests + /// + [TestClass] + public class NTLMAuthenticationTests + { + [TestMethod] + public void LMv1HashTest() + { + byte[] hash = NTLMCryptography.LMOWFv1("Password"); + byte[] expected = new byte[] { 0xe5, 0x2c, 0xac, 0x67, 0x41, 0x9a, 0x9a, 0x22, 0x4a, 0x3b, 0x10, 0x8f, 0x3f, 0xa6, 0xcb, 0x6d }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(hash, expected)); + } + + [TestMethod] + public void NTv1HashTest() + { + byte[] hash = NTLMCryptography.NTOWFv1("Password"); + byte[] expected = new byte[] { 0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca, 0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52 }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(hash, expected)); + } + + [TestMethod] + public void NTv2HashTest() + { + byte[] hash = NTLMCryptography.NTOWFv2("Password", "User", "Domain"); + byte[] expected = new byte[] { 0x0c, 0x86, 0x8a, 0x40, 0x3b, 0xfd, 0x7a, 0x93, 0xa3, 0x00, 0x1e, 0xf2, 0x2e, 0xf0, 0x2e, 0x3f }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(hash, expected)); + } + + [TestMethod] + public void LMv1ResponseTest() + { + byte[] challenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + byte[] response = NTLMCryptography.ComputeLMv1Response(challenge, "Password"); + byte[] expected = { 0x98, 0xde, 0xf7, 0xb8, 0x7f, 0x88, 0xaa, 0x5d, 0xaf, 0xe2, 0xdf, 0x77, 0x96, 0x88, 0xa1, 0x72, 0xde, 0xf1, 0x1c, 0x7d, 0x5c, 0xcd, 0xef, 0x13 }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(response, expected)); + } + + [TestMethod] + public void NTLMv1ResponseTest() + { + byte[] challenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + byte[] response = NTLMCryptography.ComputeNTLMv1Response(challenge, "Password"); + byte[] expected = { 0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6, 0x4f, 0x16, 0x33, 0x1c, 0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94}; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(response, expected)); + } + + [TestMethod] + public void LMv2ResponseTest() + { + byte[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + byte[] clientChallenge = new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; + byte[] response = NTLMCryptography.ComputeLMv2Response(serverChallenge, clientChallenge, "Password", "User", "Domain"); + byte[] expected = new byte[] { 0x86, 0xc3, 0x50, 0x97, 0xac, 0x9c, 0xec, 0x10, 0x25, 0x54, 0x76, 0x4a, 0x57, 0xcc, 0xcc, 0x19, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(response, expected)); + } + + [TestMethod] + public void NTLMv2ResponseTest() + { + byte[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + byte[] clientChallenge = new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; + DateTime time = DateTime.FromFileTimeUtc(0); // same as new byte[8] + NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(time, clientChallenge, "Domain", "Server"); + byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded(); + byte[] clientNTProof = NTLMCryptography.ComputeNTLMv2Proof(serverChallenge, clientChallengeStructurePadded, "Password", "User", "Domain"); + + byte[] expectedNTProof = new byte[] { 0x68, 0xcd, 0x0a, 0xb8, 0x51, 0xe5, 0x1c, 0x96, 0xaa, 0xbc, 0x92, 0x7b, 0xeb, 0xef, 0x6a, 0x1c }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(clientNTProof, expectedNTProof)); + } + + [TestMethod] + public void NTLMv2ChallengeMessageTest() + { + byte[] expected = new byte[]{0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x37, 0x82, 0x8a, 0xe2, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x24, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x70, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00}; + + byte[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + ChallengeMessage message = new ChallengeMessage(); + message.ServerChallenge = serverChallenge; + message.Version = new NTLMVersion(6, 0, 6000, NTLMVersion.NTLMSSP_REVISION_W2K3); + message.NegotiateFlags = NegotiateFlags.UnicodeEncoding | NegotiateFlags.OEMEncoding | NegotiateFlags.TargetNameSupplied | NegotiateFlags.Sign | NegotiateFlags.Seal | NegotiateFlags.NTLMSessionSecurity | NegotiateFlags.AlwaysSign | NegotiateFlags.TargetTypeServer | NegotiateFlags.ExtendedSessionSecurity | NegotiateFlags.TargetInfo | NegotiateFlags.Version | NegotiateFlags.Use128BitEncryption | NegotiateFlags.KeyExchange | NegotiateFlags.Use56BitEncryption; + message.TargetName = "Server"; + message.TargetInfo = AVPairUtils.GetAVPairSequence("Domain", "Server"); + + byte[] messageBytes = message.GetBytes(); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(expected, messageBytes)); + } + + [TestMethod] + public void NTLMv2AuthenticateMessageTest() + { + byte[] expected = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x54, 0x00, 0x54, 0x00, 0x84, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x35, 0x82, 0x88, 0xe2, + 0x05, 0x01, 0x28, 0x0a, 0x00, 0x00, 0x00, 0x0f, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x43, 0x00, 0x4f, 0x00, + 0x4d, 0x00, 0x50, 0x00, 0x55, 0x00, 0x54, 0x00, 0x45, 0x00, 0x52, 0x00, 0x86, 0xc3, 0x50, 0x97, + 0xac, 0x9c, 0xec, 0x10, 0x25, 0x54, 0x76, 0x4a, 0x57, 0xcc, 0xcc, 0x19, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x68, 0xcd, 0x0a, 0xb8, 0x51, 0xe5, 0x1c, 0x96, 0xaa, 0xbc, 0x92, 0x7b, + 0xeb, 0xef, 0x6a, 0x1c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, + 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xda, 0xd2, 0x54, 0x4f, 0xc9, 0x79, 0x90, + 0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9, 0xd0, 0x3e}; + + AuthenticateMessage cmp = new AuthenticateMessage(expected); + + byte[] sessionKey = {0xc5, 0xda, 0xd2, 0x54, 0x4f, 0xc9, 0x79, 0x90, 0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9, 0xd0, 0x3e}; + byte[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + byte[] clientChallenge = new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; + DateTime time = DateTime.FromFileTimeUtc(0); // same as new byte[8] + NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(time, clientChallenge, "Domain", "Server"); + byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded(); + byte[] clientNTProof = NTLMCryptography.ComputeNTLMv2Proof(serverChallenge, clientChallengeStructurePadded, "Password", "User", "Domain"); + + AuthenticateMessage message = new AuthenticateMessage(); + message.EncryptedRandomSessionKey = sessionKey; + message.Version = new NTLMVersion(5, 1, 2600, NTLMVersion.NTLMSSP_REVISION_W2K3); + message.NegotiateFlags = NegotiateFlags.UnicodeEncoding | NegotiateFlags.TargetNameSupplied | NegotiateFlags.Sign | NegotiateFlags.Seal | NegotiateFlags.NTLMSessionSecurity | NegotiateFlags.AlwaysSign | NegotiateFlags.ExtendedSessionSecurity | NegotiateFlags.TargetInfo | NegotiateFlags.Version | NegotiateFlags.Use128BitEncryption | NegotiateFlags.KeyExchange | NegotiateFlags.Use56BitEncryption; + message.DomainName = "Domain"; + message.WorkStation = "COMPUTER"; + message.UserName = "User"; + message.LmChallengeResponse = NTLMCryptography.ComputeLMv2Response(serverChallenge, clientChallenge, "Password", "User", "Domain"); + message.NtChallengeResponse = ByteUtils.Concatenate(clientNTProof, clientChallengeStructurePadded); + + byte[] messageBytes = message.GetBytes(); + // The payload entries may be distributed differently so we use cmp.GetBytes() + Assert.IsTrue(ByteUtils.AreByteArraysEqual(messageBytes, cmp.GetBytes())); + } + + public void TestAll() + { + LMv1HashTest(); + NTv1HashTest(); + NTv2HashTest(); + LMv1ResponseTest(); + NTLMv1ResponseTest(); + LMv2ResponseTest(); + NTLMv2ResponseTest(); + NTLMv2ChallengeMessageTest(); + NTLMv2AuthenticateMessageTest(); + } + } +} diff --git a/SMBLibrary.Tests/NTLM/NTLMSigningTests.cs b/SMBLibrary.Tests/NTLM/NTLMSigningTests.cs new file mode 100644 index 0000000..50433d0 --- /dev/null +++ b/SMBLibrary.Tests/NTLM/NTLMSigningTests.cs @@ -0,0 +1,240 @@ +/* Copyright (C) 2017-2019 Tal Aloni . 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.Security.Cryptography; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SMBLibrary.Authentication.NTLM; +using Utilities; + +namespace SMBLibrary.Tests +{ + [TestClass] + public class NTLMSigningTests + { + [TestMethod] + public void TestLMMIC() + { + string password = "Password"; + byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x01, 0xb1, 0x1d, 0x00, 0x00, 0x00, 0x0f}; + byte[] type2 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x95, 0x00, 0x82, 0xa2, 0x28, 0x96, 0xe3, 0x6a, 0xd1, 0xb7, 0x74, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x05, 0x02, 0xce, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x02, 0x00, + 0x06, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x06, 0x00, 0x54, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00}; + byte[] type3 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x95, 0x00, 0x80, 0xa2, + 0x06, 0x01, 0xb1, 0x1d, 0x00, 0x00, 0x00, 0x0f, 0x4e, 0x65, 0x54, 0xe6, 0xb3, 0xdc, 0xdc, 0x16, + 0xef, 0xc4, 0xd0, 0x03, 0x3b, 0x81, 0x61, 0x6f, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x37, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x54, 0x00, + 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x37, 0x00, 0xc1, 0xd1, 0x06, 0x56, + 0xa3, 0xa9, 0x64, 0x14, 0x0e, 0x7f, 0x43, 0x19, 0x3f, 0x29, 0xf3, 0x72, 0xa3, 0xc1, 0xbe, 0x02, + 0xd0, 0x6f, 0xff, 0x20, 0xc1, 0xd1, 0x06, 0x56, 0xa3, 0xa9, 0x64, 0x14, 0x0e, 0x7f, 0x43, 0x19, + 0x3f, 0x29, 0xf3, 0x72, 0xa3, 0xc1, 0xbe, 0x02, 0xd0, 0x6f, 0xff, 0x20}; + + byte[] serverChallenge = new ChallengeMessage(type2).ServerChallenge; + AuthenticateMessage authenticateMessage = new AuthenticateMessage(type3); + byte[] sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password)); + byte[] lmowf = NTLMCryptography.LMOWFv1(password); + byte[] exportedSessionKey = GetExportedSessionKey(sessionBaseKey, authenticateMessage, serverChallenge, lmowf); + + // https://msdn.microsoft.com/en-us/library/cc236695.aspx + const int micFieldOffset = 72; + ByteWriter.WriteBytes(type3, micFieldOffset, new byte[16]); + byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(type1, type2), type3); + byte[] mic = new HMACMD5(exportedSessionKey).ComputeHash(temp); + byte[] expected = new byte[] { 0x4e, 0x65, 0x54, 0xe6, 0xb3, 0xdc, 0xdc, 0x16, 0xef, 0xc4, 0xd0, 0x03, 0x3b, 0x81, 0x61, 0x6f }; + + Assert.IsTrue(ByteUtils.AreByteArraysEqual(mic, expected)); + } + + [TestMethod] + public void TestNTLMv1MIC() + { + string password = "Password"; + byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x39, 0x38, 0x00, 0x00, 0x00, 0x0f}; + byte[] type2 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x15, 0x02, 0x82, 0xa2, 0xe8, 0xbe, 0x2f, 0x5b, 0xc5, 0xe9, 0xf7, 0xa7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x05, 0x02, 0xce, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x02, 0x00, + 0x06, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x06, 0x00, 0x54, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00}; + byte[] type3 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x15, 0x02, 0x80, 0xa2, + 0x0a, 0x00, 0x39, 0x38, 0x00, 0x00, 0x00, 0x0f, 0xae, 0xa7, 0xba, 0x44, 0x4e, 0x93, 0xa7, 0xdb, + 0xb3, 0x0c, 0x85, 0x49, 0xc2, 0x2b, 0xba, 0x9a, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x54, 0x00, + 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0xa6, 0x71, 0xbd, 0x94, + 0x78, 0x4f, 0x05, 0xf1, 0x3f, 0x3a, 0x7b, 0x41, 0xcf, 0x53, 0x2e, 0x36, 0x73, 0xe2, 0x14, 0x53, + 0xbd, 0x42, 0x5e, 0x8f, 0xa6, 0x71, 0xbd, 0x94, 0x78, 0x4f, 0x05, 0xf1, 0x3f, 0x3a, 0x7b, 0x41, + 0xcf, 0x53, 0x2e, 0x36, 0x73, 0xe2, 0x14, 0x53, 0xbd, 0x42, 0x5e, 0x8f}; + + byte[] serverChallenge = new ChallengeMessage(type2).ServerChallenge; + AuthenticateMessage authenticateMessage = new AuthenticateMessage(type3); + byte[] sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password)); + byte[] lmowf = NTLMCryptography.LMOWFv1(password); + byte[] exportedSessionKey = GetExportedSessionKey(sessionBaseKey, authenticateMessage, serverChallenge, lmowf); + + // https://msdn.microsoft.com/en-us/library/cc236695.aspx + const int micFieldOffset = 72; + ByteWriter.WriteBytes(type3, micFieldOffset, new byte[16]); + byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(type1, type2), type3); + byte[] mic = new HMACMD5(exportedSessionKey).ComputeHash(temp); + byte[] expected = new byte[] { 0xae, 0xa7, 0xba, 0x44, 0x4e, 0x93, 0xa7, 0xdb, 0xb3, 0x0c, 0x85, 0x49, 0xc2, 0x2b, 0xba, 0x9a }; + + Assert.IsTrue(ByteUtils.AreByteArraysEqual(mic, expected)); + } + + [TestMethod] + public void TestNTLMv1ExtendedSessionSecurityKeyExchangeMIC() + { + string password = "Password"; + byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0f}; + byte[] type2 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x8a, 0xe2, 0x7a, 0x6d, 0x47, 0x52, 0x11, 0x8b, 0x9f, 0x37, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x71, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x02, 0x00, 0x10, 0x00, 0x54, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x04, 0x00, 0x10, 0x00, 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, + 0x31, 0x00, 0x30, 0x00, 0x03, 0x00, 0x10, 0x00, 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x07, 0x00, 0x08, 0x00, 0x28, 0x9a, 0x19, 0xec, + 0x8d, 0x92, 0xd2, 0x01, 0x00, 0x00, 0x00, 0x00}; + byte[] type3 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xac, 0x00, 0x00, 0x00, 0x15, 0x82, 0x88, 0xe2, + 0x0a, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0f, 0xc6, 0x21, 0x82, 0x59, 0x83, 0xda, 0xc7, 0xe7, + 0xfa, 0x96, 0x44, 0x67, 0x16, 0xc3, 0xb3, 0x5b, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x54, 0x00, + 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0x90, 0x13, 0xb0, 0x36, + 0xa4, 0xa5, 0xf0, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0x46, 0xea, 0x77, 0x30, 0x44, 0xee, 0xa5, 0x98, 0x26, 0xa0, 0x93, + 0x71, 0x5c, 0x83, 0xff, 0x76, 0x70, 0x1d, 0xf0, 0xb8, 0xa0, 0xad, 0x4d, 0xac, 0xe9, 0xf4, 0x5c, + 0x3e, 0xb1, 0xb6, 0x48, 0x08, 0xa0, 0x46, 0x8c, 0x31, 0xe1, 0x2d, 0x60}; + + byte[] serverChallenge = new ChallengeMessage(type2).ServerChallenge; + AuthenticateMessage authenticateMessage = new AuthenticateMessage(type3); + byte[] sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password)); + byte[] lmowf = NTLMCryptography.LMOWFv1(password); + byte[] exportedSessionKey = GetExportedSessionKey(sessionBaseKey, authenticateMessage, serverChallenge, lmowf); + + // https://msdn.microsoft.com/en-us/library/cc236695.aspx + const int micFieldOffset = 72; + ByteWriter.WriteBytes(type3, micFieldOffset, new byte[16]); + byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(type1, type2), type3); + byte[] mic = new HMACMD5(exportedSessionKey).ComputeHash(temp); + byte[] expected = new byte[] { 0xc6, 0x21, 0x82, 0x59, 0x83, 0xda, 0xc7, 0xe7, 0xfa, 0x96, 0x44, 0x67, 0x16, 0xc3, 0xb3, 0x5b }; + + Assert.IsTrue(ByteUtils.AreByteArraysEqual(mic, expected)); + } + + [TestMethod] + public void TestNTLMv2KeyExchangeMIC() + { + byte[] responseKeyNT = NTLMCryptography.NTOWFv2("Password", "User", "TAL-VM6"); + byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0f}; + byte[] type2 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x8a, 0xe2, 0x63, 0x74, 0x79, 0x77, 0xe1, 0xea, 0x35, 0x51, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x71, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x02, 0x00, 0x10, 0x00, 0x54, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x04, 0x00, 0x10, 0x00, 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, + 0x31, 0x00, 0x30, 0x00, 0x03, 0x00, 0x10, 0x00, 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x07, 0x00, 0x08, 0x00, 0x1f, 0x8a, 0xd4, 0xff, + 0x01, 0x91, 0xd2, 0x01, 0x00, 0x00, 0x00, 0x00}; + byte[] type3 = new byte[] { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x01, 0x94, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x96, 0x01, 0x00, 0x00, 0x15, 0x82, 0x88, 0xe2, + 0x0a, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0f, 0x82, 0x3c, 0xff, 0x48, 0xa9, 0x03, 0x13, 0x4c, + 0x33, 0x3c, 0x09, 0x87, 0xf3, 0x16, 0x59, 0x89, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x54, 0x00, + 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb3, 0x06, 0x65, 0xe3, 0x9f, 0x03, 0xe1, 0xc3, 0xd8, 0x28, 0x7c, 0x9c, + 0x35, 0x0d, 0x32, 0x4c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8a, 0xd4, 0xff, + 0x01, 0x91, 0xd2, 0x01, 0x77, 0x71, 0x91, 0x94, 0xb1, 0x6e, 0x66, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x10, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, + 0x31, 0x00, 0x30, 0x00, 0x01, 0x00, 0x10, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x2d, 0x00, + 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x04, 0x00, 0x10, 0x00, 0x54, 0x00, 0x61, 0x00, + 0x6c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x03, 0x00, 0x10, 0x00, + 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x07, 0x00, 0x08, 0x00, 0x1f, 0x8a, 0xd4, 0xff, 0x01, 0x91, 0xd2, 0x01, 0x06, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x19, 0x0d, 0x73, 0xca, 0x97, 0x30, 0x2a, 0xa7, + 0x7a, 0x1f, 0xb6, 0xad, 0xe2, 0xe5, 0x4a, 0x59, 0x4a, 0x93, 0x7e, 0x37, 0xcd, 0x0c, 0xd7, 0x90, + 0x25, 0xc4, 0xaf, 0x8a, 0x17, 0x99, 0x69, 0x56, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x1a, 0x00, + 0x63, 0x00, 0x69, 0x00, 0x66, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x61, 0x00, 0x6c, 0x00, + 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x7c, 0xce, 0x0b, 0x92, 0x46, 0x46, 0x0d, 0x5b, 0x3b, + 0x11, 0xb4, 0xde, 0x86, 0x28, 0x11}; + + byte[] serverChallenge = new ChallengeMessage(type2).ServerChallenge; + AuthenticateMessage authenticateMessage = new AuthenticateMessage(type3); + byte[] ntProofStr = ByteReader.ReadBytes(authenticateMessage.NtChallengeResponse, 0, 16); + byte[] sessionBaseKey = new HMACMD5(responseKeyNT).ComputeHash(ntProofStr); + byte[] exportedSessionKey = GetExportedSessionKey(sessionBaseKey, authenticateMessage, serverChallenge, null); + + // https://msdn.microsoft.com/en-us/library/cc236695.aspx + const int micFieldOffset = 72; + ByteWriter.WriteBytes(type3, micFieldOffset, new byte[16]); + byte[] temp = ByteUtils.Concatenate(ByteUtils.Concatenate(type1, type2), type3); + byte[] mic = new HMACMD5(exportedSessionKey).ComputeHash(temp); + byte[] expected = new byte[] { 0x82, 0x3c, 0xff, 0x48, 0xa9, 0x03, 0x13, 0x4c, 0x33, 0x3c, 0x09, 0x87, 0xf3, 0x16, 0x59, 0x89 }; + + Assert.IsTrue(ByteUtils.AreByteArraysEqual(mic, expected)); + } + + public void TestAll() + { + TestLMMIC(); + TestNTLMv1MIC(); + TestNTLMv1ExtendedSessionSecurityKeyExchangeMIC(); + TestNTLMv2KeyExchangeMIC(); + } + + private static byte[] GetExportedSessionKey(byte[] sessionBaseKey, AuthenticateMessage message, byte[] serverChallenge, byte[] lmowf) + { + byte[] keyExchangeKey; + if (AuthenticationMessageUtils.IsNTLMv2NTResponse(message.NtChallengeResponse)) + { + keyExchangeKey = sessionBaseKey; + } + else + { + keyExchangeKey = NTLMCryptography.KXKey(sessionBaseKey, message.NegotiateFlags, message.LmChallengeResponse, serverChallenge, lmowf); + } + + if ((message.NegotiateFlags & NegotiateFlags.KeyExchange) > 0) + { + return RC4.Decrypt(keyExchangeKey, message.EncryptedRandomSessionKey); + } + else + { + return keyExchangeKey; + } + } + } +} diff --git a/SMBLibrary.Tests/NTLM/RC4Tests.cs b/SMBLibrary.Tests/NTLM/RC4Tests.cs new file mode 100644 index 0000000..4fa43b9 --- /dev/null +++ b/SMBLibrary.Tests/NTLM/RC4Tests.cs @@ -0,0 +1,136 @@ +/* Copyright (C) 2017-2019 Tal Aloni . 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.Security.Cryptography; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Utilities; + +namespace SMBLibrary.Tests +{ + /// + /// https://tools.ietf.org/id/draft-kaukonen-cipher-arcfour-03.txt + /// Test Vectors from Appendix A + /// + [TestClass] + public class RC4Tests + { + [TestMethod] + public void Test1() + { + byte[] key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + byte[] text = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + byte[] expectedCipher = new byte[] { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }; + byte[] cipher = RC4.Encrypt(key, text); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(cipher, expectedCipher)); + } + + [TestMethod] + public void Test2() + { + byte[] key = new byte[] { 0x61, 0x8A, 0x63, 0xD2, 0xFB }; + byte[] text = new byte[] { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C }; + byte[] expectedCipher = new byte[] { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; + byte[] cipher = RC4.Encrypt(key, text); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(cipher, expectedCipher)); + } + + [TestMethod] + public void Test3() + { + byte[] key = new byte[] { 0x29, 0x04, 0x19, 0x72, 0xFB, 0x42, 0xBA, 0x5F, + 0xC7, 0x12, 0x77, 0x12, 0xF1, 0x38, 0x29, 0xC9}; + byte[] text = new byte[] { 0x52, 0x75, 0x69, 0x73, 0x6c, 0x69, 0x6e, 0x6e, + 0x75, 0x6e, 0x20, 0x6c, 0x61, 0x75, 0x6c, 0x75, + 0x20, 0x6b, 0x6f, 0x72, 0x76, 0x69, 0x73, 0x73, + 0x73, 0x61, 0x6e, 0x69, 0x2c, 0x20, 0x74, 0xe4, + 0x68, 0x6b, 0xe4, 0x70, 0xe4, 0x69, 0x64, 0x65, + 0x6e, 0x20, 0x70, 0xe4, 0xe4, 0x6c, 0x6c, 0xe4, + 0x20, 0x74, 0xe4, 0x79, 0x73, 0x69, 0x6b, 0x75, + 0x75, 0x2e, 0x20, 0x4b, 0x65, 0x73, 0xe4, 0x79, + 0xf6, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, + 0x6e, 0x69, 0x20, 0x6f, 0x6d, 0x61, 0x6e, 0x61, + 0x6e, 0x69, 0x2c, 0x20, 0x6b, 0x61, 0x73, 0x6b, + 0x69, 0x73, 0x61, 0x76, 0x75, 0x75, 0x6e, 0x20, + 0x6c, 0x61, 0x61, 0x6b, 0x73, 0x6f, 0x74, 0x20, + 0x76, 0x65, 0x72, 0x68, 0x6f, 0x75, 0x75, 0x2e, + 0x20, 0x45, 0x6e, 0x20, 0x6d, 0x61, 0x20, 0x69, + 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x65, 0x2c, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6f, + 0x6b, 0x61, 0x61, 0x2c, 0x20, 0x6d, 0x75, 0x74, + 0x74, 0x61, 0x20, 0x6d, 0x65, 0x74, 0x73, 0xe4, + 0x6e, 0x20, 0x74, 0x75, 0x6d, 0x6d, 0x75, 0x75, + 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x75, 0x6f, 0x6b, 0x61, 0x61, 0x2e, 0x20, + 0x50, 0x75, 0x75, 0x6e, 0x74, 0x6f, 0x20, 0x70, + 0x69, 0x6c, 0x76, 0x65, 0x6e, 0x2c, 0x20, 0x6d, + 0x69, 0x20, 0x68, 0x75, 0x6b, 0x6b, 0x75, 0x75, + 0x2c, 0x20, 0x73, 0x69, 0x69, 0x6e, 0x74, 0x6f, + 0x20, 0x76, 0x61, 0x72, 0x61, 0x6e, 0x20, 0x74, + 0x75, 0x75, 0x6c, 0x69, 0x73, 0x65, 0x6e, 0x2c, + 0x20, 0x6d, 0x69, 0x20, 0x6e, 0x75, 0x6b, 0x6b, + 0x75, 0x75, 0x2e, 0x20, 0x54, 0x75, 0x6f, 0x6b, + 0x73, 0x75, 0x74, 0x20, 0x76, 0x61, 0x6e, 0x61, + 0x6d, 0x6f, 0x6e, 0x20, 0x6a, 0x61, 0x20, 0x76, + 0x61, 0x72, 0x6a, 0x6f, 0x74, 0x20, 0x76, 0x65, + 0x65, 0x6e, 0x2c, 0x20, 0x6e, 0x69, 0x69, 0x73, + 0x74, 0xe4, 0x20, 0x73, 0x79, 0x64, 0xe4, 0x6d, + 0x65, 0x6e, 0x69, 0x20, 0x6c, 0x61, 0x75, 0x6c, + 0x75, 0x6e, 0x20, 0x74, 0x65, 0x65, 0x6e, 0x2e, + 0x20, 0x2d, 0x20, 0x45, 0x69, 0x6e, 0x6f, 0x20, + 0x4c, 0x65, 0x69, 0x6e, 0x6f}; + byte[] expectedCipher = new byte[] { 0x35, 0x81, 0x86, 0x99, 0x90, 0x01, 0xe6, 0xb5, + 0xda, 0xf0, 0x5e, 0xce, 0xeb, 0x7e, 0xee, 0x21, + 0xe0, 0x68, 0x9c, 0x1f, 0x00, 0xee, 0xa8, 0x1f, + 0x7d, 0xd2, 0xca, 0xae, 0xe1, 0xd2, 0x76, 0x3e, + 0x68, 0xaf, 0x0e, 0xad, 0x33, 0xd6, 0x6c, 0x26, + 0x8b, 0xc9, 0x46, 0xc4, 0x84, 0xfb, 0xe9, 0x4c, + 0x5f, 0x5e, 0x0b, 0x86, 0xa5, 0x92, 0x79, 0xe4, + 0xf8, 0x24, 0xe7, 0xa6, 0x40, 0xbd, 0x22, 0x32, + 0x10, 0xb0, 0xa6, 0x11, 0x60, 0xb7, 0xbc, 0xe9, + 0x86, 0xea, 0x65, 0x68, 0x80, 0x03, 0x59, 0x6b, + 0x63, 0x0a, 0x6b, 0x90, 0xf8, 0xe0, 0xca, 0xf6, + 0x91, 0x2a, 0x98, 0xeb, 0x87, 0x21, 0x76, 0xe8, + 0x3c, 0x20, 0x2c, 0xaa, 0x64, 0x16, 0x6d, 0x2c, + 0xce, 0x57, 0xff, 0x1b, 0xca, 0x57, 0xb2, 0x13, + 0xf0, 0xed, 0x1a, 0xa7, 0x2f, 0xb8, 0xea, 0x52, + 0xb0, 0xbe, 0x01, 0xcd, 0x1e, 0x41, 0x28, 0x67, + 0x72, 0x0b, 0x32, 0x6e, 0xb3, 0x89, 0xd0, 0x11, + 0xbd, 0x70, 0xd8, 0xaf, 0x03, 0x5f, 0xb0, 0xd8, + 0x58, 0x9d, 0xbc, 0xe3, 0xc6, 0x66, 0xf5, 0xea, + 0x8d, 0x4c, 0x79, 0x54, 0xc5, 0x0c, 0x3f, 0x34, + 0x0b, 0x04, 0x67, 0xf8, 0x1b, 0x42, 0x59, 0x61, + 0xc1, 0x18, 0x43, 0x07, 0x4d, 0xf6, 0x20, 0xf2, + 0x08, 0x40, 0x4b, 0x39, 0x4c, 0xf9, 0xd3, 0x7f, + 0xf5, 0x4b, 0x5f, 0x1a, 0xd8, 0xf6, 0xea, 0x7d, + 0xa3, 0xc5, 0x61, 0xdf, 0xa7, 0x28, 0x1f, 0x96, + 0x44, 0x63, 0xd2, 0xcc, 0x35, 0xa4, 0xd1, 0xb0, + 0x34, 0x90, 0xde, 0xc5, 0x1b, 0x07, 0x11, 0xfb, + 0xd6, 0xf5, 0x5f, 0x79, 0x23, 0x4d, 0x5b, 0x7c, + 0x76, 0x66, 0x22, 0xa6, 0x6d, 0xe9, 0x2b, 0xe9, + 0x96, 0x46, 0x1d, 0x5e, 0x4d, 0xc8, 0x78, 0xef, + 0x9b, 0xca, 0x03, 0x05, 0x21, 0xe8, 0x35, 0x1e, + 0x4b, 0xae, 0xd2, 0xfd, 0x04, 0xf9, 0x46, 0x73, + 0x68, 0xc4, 0xad, 0x6a, 0xc1, 0x86, 0xd0, 0x82, + 0x45, 0xb2, 0x63, 0xa2, 0x66, 0x6d, 0x1f, 0x6c, + 0x54, 0x20, 0xf1, 0x59, 0x9d, 0xfd, 0x9f, 0x43, + 0x89, 0x21, 0xc2, 0xf5, 0xa4, 0x63, 0x93, 0x8c, + 0xe0, 0x98, 0x22, 0x65, 0xee, 0xf7, 0x01, 0x79, + 0xbc, 0x55, 0x3f, 0x33, 0x9e, 0xb1, 0xa4, 0xc1, + 0xaf, 0x5f, 0x6a, 0x54, 0x7f}; + byte[] cipher = RC4.Encrypt(key, text); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(cipher, expectedCipher)); + } + + public void TestAll() + { + Test1(); + Test2(); + Test3(); + } + } +} diff --git a/SMBLibrary.Tests/NetBiosTests.cs b/SMBLibrary.Tests/NetBiosTests.cs new file mode 100644 index 0000000..d3f8fc4 --- /dev/null +++ b/SMBLibrary.Tests/NetBiosTests.cs @@ -0,0 +1,44 @@ +/* Copyright (C) 2017-2019 Tal Aloni . 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 Microsoft.VisualStudio.TestTools.UnitTesting; +using SMBLibrary.NetBios; +using Utilities; + +namespace SMBLibrary.Tests +{ + [TestClass] + public class NetBiosTests + { + [TestMethod] + public void Test1() + { + byte[] buffer = new byte[] { 0x20, 0x46, 0x47, 0x45, 0x4e, 0x44, 0x4a, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x00 }; + int offset = 0; + string name = NetBiosUtils.DecodeName(buffer, ref offset); + byte[] encodedName = NetBiosUtils.EncodeName(name, String.Empty); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, encodedName)); + } + + [TestMethod] + public void Test2() + { + byte[] buffer = new byte[] { 0x20, 0x46, 0x47, 0x45, 0x4e, 0x44, 0x4a, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 0x41, 0x00 }; + int offset = 0; + string name = NetBiosUtils.DecodeName(buffer, ref offset); + byte[] encodedName = NetBiosUtils.EncodeName(name, String.Empty); + Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, encodedName)); + } + + public void TestAll() + { + Test1(); + Test2(); + } + } +} diff --git a/SMBLibrary.Tests/Program.cs b/SMBLibrary.Tests/Program.cs new file mode 100644 index 0000000..14fd6f4 --- /dev/null +++ b/SMBLibrary.Tests/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace SMBLibrary.Tests +{ + class Program + { + static void Main(string[] args) + { + new NTLMAuthenticationTests().TestAll(); + new NTLMSigningTests().TestAll(); + new RC4Tests().TestAll(); + + new NetBiosTests().TestAll(); + new RPCTests().TestAll(); + new SMB2SigningTests().TestAll(); + } + } +} diff --git a/SMBLibrary.Tests/Properties/AssemblyInfo.cs b/SMBLibrary.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..abd6321 --- /dev/null +++ b/SMBLibrary.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SMBLibrary.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Tal Aloni")] +[assembly: AssemblyProduct("SMBLibrary.Tests")] +[assembly: AssemblyCopyright("Copyright © Tal Aloni 2014-2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8ab9297a-1e84-4d7e-a080-cf2fbaf9af1d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SMBLibrary.Tests/RPCTests.cs b/SMBLibrary.Tests/RPCTests.cs new file mode 100644 index 0000000..bcda875 --- /dev/null +++ b/SMBLibrary.Tests/RPCTests.cs @@ -0,0 +1,110 @@ +/* Copyright (C) 2014-2019 Tal Aloni . 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 Microsoft.VisualStudio.TestTools.UnitTesting; +using SMBLibrary.RPC; +using SMBLibrary.Services; +using Utilities; + +namespace SMBLibrary.Tests +{ + [TestClass] + public class RPCTests + { + [TestMethod] + public void Test1() + { + byte[] buffer = new byte[]{ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x32, 0x00, + 0x2d, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x37, 0x00, 0x00, 0x00, 0xcd, 0xab, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x4b, 0x00, + 0x47, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x55, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + NetrWkstaGetInfoResponse response = new NetrWkstaGetInfoResponse(buffer); + + byte[] responseBytes = response.GetBytes(); + //Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, responseBytes)); + } + + [TestMethod] + public void Test2() + { + byte[] buffer = new byte[] { 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x90, 0x84, 0x00, 0x08, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 }; + NetrServerGetInfoResponse response = new NetrServerGetInfoResponse(buffer); + + byte[] responseBytes = response.GetBytes(); + //Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, responseBytes)); + } + + [TestMethod] + public void Test3() + { + byte[] buffer = new byte[] {0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, + 0x38, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; + NetrShareEnumRequest request = new NetrShareEnumRequest(buffer); + + byte[] requestBytes = request.GetBytes(); + //Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, requestBytes)); + } + + [TestMethod] + public void Test4() + { + byte[] buffer = new byte[] {0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x0c, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, + 0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x80, 0x1c, 0x00, 0x02, 0x00, 0x20, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x24, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x69, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00, + 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x20, 0x00, 0x73, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00, + 0x43, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x20, 0x00, 0x49, 0x00, 0x50, 0x00, 0x43, 0x00, 0x00, 0x00, 0x68, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x49, 0x00, + 0x4e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + NetrShareEnumResponse response = new NetrShareEnumResponse(buffer); + + byte[] responseBytes = response.GetBytes(); + //Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, responseBytes)); + } + + [TestMethod] + public void Test5() + { + byte[] buffer = new byte[] {0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, + 0x38, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, + 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0xb7, 0x6c, 0x02, 0x00, 0x00, 0x00}; + NetrShareGetInfoRequest request = new NetrShareGetInfoRequest(buffer); + + byte[] requestBytes = request.GetBytes(); + //Assert.IsTrue(ByteUtils.AreByteArraysEqual(buffer, requestBytes)); + } + + public void TestAll() + { + Test1(); + Test2(); + Test3(); + Test4(); + Test5(); + } + } +} diff --git a/SMBLibrary.Tests/SMB2SigningTests.cs b/SMBLibrary.Tests/SMB2SigningTests.cs new file mode 100644 index 0000000..8a6890b --- /dev/null +++ b/SMBLibrary.Tests/SMB2SigningTests.cs @@ -0,0 +1,62 @@ +/* Copyright (C) 2017-2019 Tal Aloni . 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.Security.Cryptography; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Utilities; + +namespace SMBLibrary.Tests +{ + [TestClass] + public class SMB2SigningTests + { + [TestMethod] + public void Test1() + { + byte[] exportedSessionKey = new byte[] { 0xD3, 0x83, 0x54, 0xCC, 0x37, 0x43, 0x39, 0xF0, 0x52, 0x4F, 0x78, 0x91, 0x46, 0x78, 0x99, 0x21 }; + + byte[] message = new byte[]{0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x01, 0x00, 0x28, 0x01, 0x00, 0xc0, 0x0b, 0x00, 0x07, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xfe, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xfb, 0xd2, 0x84, 0x34, 0x03, 0x24, 0xc6, 0x2f, 0xbe, 0xbb, 0x65, 0xdd, 0x10, 0x51, 0xf3, 0xae, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + ByteWriter.WriteBytes(message, 48, new byte[16]); + + byte[] signature = new HMACSHA256(exportedSessionKey).ComputeHash(message); + signature = ByteReader.ReadBytes(signature, 0, 16); + byte[] expected = new byte[] { 0xfb, 0xd2, 0x84, 0x34, 0x03, 0x24, 0xc6, 0x2f, 0xbe, 0xbb, 0x65, 0xdd, 0x10, 0x51, 0xf3, 0xae }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(signature, expected)); + } + + [TestMethod] + public void Test2() + { + byte[] exportedSessionKey = new byte[] { 0x04, 0xE7, 0x07, 0x57, 0x1F, 0x8E, 0x03, 0x53, 0xB7, 0x7A, 0x94, 0xC3, 0x65, 0x3B, 0x87, 0xB5 }; + + byte[] message = new byte[]{ 0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x01, 0x00, 0x28, 0x01, 0x00, 0xc0, 0x0b, 0x00, 0x07, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xfe, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0xa1, 0x64, 0xff, 0xe5, 0x3d, 0x68, 0x11, 0x98, 0x1f, 0x38, 0x67, 0x72, 0xe3, 0x87, 0xe0, 0x6f, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + ByteWriter.WriteBytes(message, 48, new byte[16]); + + byte[] signature = new HMACSHA256(exportedSessionKey).ComputeHash(message); + signature = ByteReader.ReadBytes(signature, 0, 16); + byte[] expected = new byte[] { 0xa1, 0x64, 0xff, 0xe5, 0x3d, 0x68, 0x11, 0x98, 0x1f, 0x38, 0x67, 0x72, 0xe3, 0x87, 0xe0, 0x6f }; + Assert.IsTrue(ByteUtils.AreByteArraysEqual(signature, expected)); + } + + public void TestAll() + { + Test1(); + Test2(); + } + } +} diff --git a/SMBLibrary.Tests/SMBLibrary.Tests.csproj b/SMBLibrary.Tests/SMBLibrary.Tests.csproj new file mode 100644 index 0000000..c184e26 --- /dev/null +++ b/SMBLibrary.Tests/SMBLibrary.Tests.csproj @@ -0,0 +1,69 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {C79B06EB-32C1-44CA-B7E1-A891B8135658} + Exe + Properties + SMBLibrary.Tests + SMBLibrary.Tests + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + Components\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + + + + + + + + + + + + + + + + {8CE25496-A52B-4841-822F-74C469D10EE7} + SMBLibrary.Win32 + + + {8D9E8F5D-FD13-4E4C-9723-A333DA2034A7} + SMBLibrary + + + {6E0F2D1E-6167-4032-BA90-DEE3A99207D0} + Utilities + + + + + \ No newline at end of file diff --git a/SMBLibrary/Authentication/NTLM/Helpers/MD4.cs b/SMBLibrary/Authentication/NTLM/Helpers/MD4.cs index 64d8ec8..3d45fba 100644 --- a/SMBLibrary/Authentication/NTLM/Helpers/MD4.cs +++ b/SMBLibrary/Authentication/NTLM/Helpers/MD4.cs @@ -50,7 +50,7 @@ namespace System.Security.Cryptography /// ///

/// - internal class MD4 + public class MD4 { // MD4 specific object variables //----------------------------------------------------------------------- diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 96d335a..d355446 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -581,12 +581,6 @@ - - - - - - diff --git a/SMBServer.sln b/SMBServer.sln index e1ac730..855ffd7 100644 --- a/SMBServer.sln +++ b/SMBServer.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utilities", "Utilities\Util EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMBLibrary.Win32", "SMBLibrary.Win32\SMBLibrary.Win32.csproj", "{8CE25496-A52B-4841-822F-74C469D10EE7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMBLibrary.Tests", "SMBLibrary.Tests\SMBLibrary.Tests.csproj", "{C79B06EB-32C1-44CA-B7E1-A891B8135658}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,10 @@ Global {8CE25496-A52B-4841-822F-74C469D10EE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CE25496-A52B-4841-822F-74C469D10EE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CE25496-A52B-4841-822F-74C469D10EE7}.Release|Any CPU.Build.0 = Release|Any CPU + {C79B06EB-32C1-44CA-B7E1-A891B8135658}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C79B06EB-32C1-44CA-B7E1-A891B8135658}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C79B06EB-32C1-44CA-B7E1-A891B8135658}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C79B06EB-32C1-44CA-B7E1-A891B8135658}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE