aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
commitbfcd1b520fd79b893e721ba916ae5e1656407d2f (patch)
tree6a05119800484435fb384da25c6390054a27c3c3 /Emby.Server.Implementations/IO/SharpCifs/Ntlmssp
parente3531534b85aeaaa3e4aaf462d5e77ea142dc762 (diff)
merge common implementations and server implementations
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Ntlmssp')
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs197
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs140
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs249
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs438
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs677
5 files changed, 1701 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs
new file mode 100644
index 0000000000..116f71b754
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs
@@ -0,0 +1,197 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+namespace SharpCifs.Ntlmssp
+{
+ /// <summary>Flags used during negotiation of NTLMSSP authentication.</summary>
+ /// <remarks>Flags used during negotiation of NTLMSSP authentication.</remarks>
+ public abstract class NtlmFlags
+ {
+ /// <summary>Indicates whether Unicode strings are supported or used.</summary>
+ /// <remarks>Indicates whether Unicode strings are supported or used.</remarks>
+ public const int NtlmsspNegotiateUnicode = unchecked(0x00000001);
+
+ /// <summary>Indicates whether OEM strings are supported or used.</summary>
+ /// <remarks>Indicates whether OEM strings are supported or used.</remarks>
+ public const int NtlmsspNegotiateOem = unchecked(0x00000002);
+
+ /// <summary>
+ /// Indicates whether the authentication target is requested from
+ /// the server.
+ /// </summary>
+ /// <remarks>
+ /// Indicates whether the authentication target is requested from
+ /// the server.
+ /// </remarks>
+ public const int NtlmsspRequestTarget = unchecked(0x00000004);
+
+ /// <summary>
+ /// Specifies that communication across the authenticated channel
+ /// should carry a digital signature (message integrity).
+ /// </summary>
+ /// <remarks>
+ /// Specifies that communication across the authenticated channel
+ /// should carry a digital signature (message integrity).
+ /// </remarks>
+ public const int NtlmsspNegotiateSign = unchecked(0x00000010);
+
+ /// <summary>
+ /// Specifies that communication across the authenticated channel
+ /// should be encrypted (message confidentiality).
+ /// </summary>
+ /// <remarks>
+ /// Specifies that communication across the authenticated channel
+ /// should be encrypted (message confidentiality).
+ /// </remarks>
+ public const int NtlmsspNegotiateSeal = unchecked(0x00000020);
+
+ /// <summary>Indicates datagram authentication.</summary>
+ /// <remarks>Indicates datagram authentication.</remarks>
+ public const int NtlmsspNegotiateDatagramStyle = unchecked(0x00000040);
+
+ /// <summary>
+ /// Indicates that the LAN Manager session key should be used for
+ /// signing and sealing authenticated communication.
+ /// </summary>
+ /// <remarks>
+ /// Indicates that the LAN Manager session key should be used for
+ /// signing and sealing authenticated communication.
+ /// </remarks>
+ public const int NtlmsspNegotiateLmKey = unchecked(0x00000080);
+
+ public const int NtlmsspNegotiateNetware = unchecked(0x00000100);
+
+ /// <summary>Indicates support for NTLM authentication.</summary>
+ /// <remarks>Indicates support for NTLM authentication.</remarks>
+ public const int NtlmsspNegotiateNtlm = unchecked(0x00000200);
+
+ /// <summary>
+ /// Indicates whether the OEM-formatted domain name in which the
+ /// client workstation has membership is supplied in the Type-1 message.
+ /// </summary>
+ /// <remarks>
+ /// Indicates whether the OEM-formatted domain name in which the
+ /// client workstation has membership is supplied in the Type-1 message.
+ /// This is used in the negotation of local authentication.
+ /// </remarks>
+ public const int NtlmsspNegotiateOemDomainSupplied = unchecked(0x00001000);
+
+ /// <summary>
+ /// Indicates whether the OEM-formatted workstation name is supplied
+ /// in the Type-1 message.
+ /// </summary>
+ /// <remarks>
+ /// Indicates whether the OEM-formatted workstation name is supplied
+ /// in the Type-1 message. This is used in the negotiation of local
+ /// authentication.
+ /// </remarks>
+ public const int NtlmsspNegotiateOemWorkstationSupplied = unchecked(0x00002000);
+
+ /// <summary>
+ /// Sent by the server to indicate that the server and client are
+ /// on the same machine.
+ /// </summary>
+ /// <remarks>
+ /// Sent by the server to indicate that the server and client are
+ /// on the same machine. This implies that the server will include
+ /// a local security context handle in the Type 2 message, for
+ /// use in local authentication.
+ /// </remarks>
+ public const int NtlmsspNegotiateLocalCall = unchecked(0x00004000);
+
+ /// <summary>
+ /// Indicates that authenticated communication between the client
+ /// and server should carry a "dummy" digital signature.
+ /// </summary>
+ /// <remarks>
+ /// Indicates that authenticated communication between the client
+ /// and server should carry a "dummy" digital signature.
+ /// </remarks>
+ public const int NtlmsspNegotiateAlwaysSign = unchecked(0x00008000);
+
+ /// <summary>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a domain.
+ /// </summary>
+ /// <remarks>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a domain.
+ /// </remarks>
+ public const int NtlmsspTargetTypeDomain = unchecked(0x00010000);
+
+ /// <summary>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a server.
+ /// </summary>
+ /// <remarks>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a server.
+ /// </remarks>
+ public const int NtlmsspTargetTypeServer = unchecked(0x00020000);
+
+ /// <summary>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a share (presumably for share-level
+ /// authentication).
+ /// </summary>
+ /// <remarks>
+ /// Sent by the server in the Type 2 message to indicate that the
+ /// target authentication realm is a share (presumably for share-level
+ /// authentication).
+ /// </remarks>
+ public const int NtlmsspTargetTypeShare = unchecked(0x00040000);
+
+ /// <summary>
+ /// Indicates that the NTLM2 signing and sealing scheme should be used
+ /// for protecting authenticated communications.
+ /// </summary>
+ /// <remarks>
+ /// Indicates that the NTLM2 signing and sealing scheme should be used
+ /// for protecting authenticated communications. This refers to a
+ /// particular session security scheme, and is not related to the use
+ /// of NTLMv2 authentication.
+ /// </remarks>
+ public const int NtlmsspNegotiateNtlm2 = unchecked(0x00080000);
+
+ public const int NtlmsspRequestInitResponse = unchecked(0x00100000);
+
+ public const int NtlmsspRequestAcceptResponse = unchecked(0x00200000);
+
+ public const int NtlmsspRequestNonNtSessionKey = unchecked(0x00400000
+ );
+
+ /// <summary>
+ /// Sent by the server in the Type 2 message to indicate that it is
+ /// including a Target Information block in the message.
+ /// </summary>
+ /// <remarks>
+ /// Sent by the server in the Type 2 message to indicate that it is
+ /// including a Target Information block in the message. The Target
+ /// Information block is used in the calculation of the NTLMv2 response.
+ /// </remarks>
+ public const int NtlmsspNegotiateTargetInfo = unchecked(0x00800000);
+
+ /// <summary>Indicates that 128-bit encryption is supported.</summary>
+ /// <remarks>Indicates that 128-bit encryption is supported.</remarks>
+ public const int NtlmsspNegotiate128 = unchecked(0x20000000);
+
+ public const int NtlmsspNegotiateKeyExch = unchecked(0x40000000);
+
+ /// <summary>Indicates that 56-bit encryption is supported.</summary>
+ /// <remarks>Indicates that 56-bit encryption is supported.</remarks>
+ public const int NtlmsspNegotiate56 = unchecked((int)(0x80000000));
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs
new file mode 100644
index 0000000000..02827d2d07
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs
@@ -0,0 +1,140 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+
+namespace SharpCifs.Ntlmssp
+{
+ /// <summary>Abstract superclass for all NTLMSSP messages.</summary>
+ /// <remarks>Abstract superclass for all NTLMSSP messages.</remarks>
+ public abstract class NtlmMessage : NtlmFlags
+ {
+ /// <summary>The NTLMSSP "preamble".</summary>
+ /// <remarks>The NTLMSSP "preamble".</remarks>
+ protected internal static readonly byte[] NtlmsspSignature = { unchecked(
+ (byte)('N')), unchecked((byte)('T')), unchecked((byte)('L')),
+ unchecked((byte)('M')), unchecked((byte)('S')), unchecked((byte
+ )('S')), unchecked((byte)('P')), unchecked(0) };
+
+ private static readonly string OemEncoding = Config.DefaultOemEncoding;
+
+ protected internal static readonly string UniEncoding = "UTF-16LE";
+
+ private int _flags;
+
+ /// <summary>Returns the flags currently in use for this message.</summary>
+ /// <remarks>Returns the flags currently in use for this message.</remarks>
+ /// <returns>
+ /// An <code>int</code> containing the flags in use for this
+ /// message.
+ /// </returns>
+ public virtual int GetFlags()
+ {
+ return _flags;
+ }
+
+ /// <summary>Sets the flags for this message.</summary>
+ /// <remarks>Sets the flags for this message.</remarks>
+ /// <param name="flags">The flags for this message.</param>
+ public virtual void SetFlags(int flags)
+ {
+ this._flags = flags;
+ }
+
+ /// <summary>Returns the status of the specified flag.</summary>
+ /// <remarks>Returns the status of the specified flag.</remarks>
+ /// <param name="flag">The flag to test (i.e., <code>NTLMSSP_NEGOTIATE_OEM</code>).</param>
+ /// <returns>A <code>boolean</code> indicating whether the flag is set.</returns>
+ public virtual bool GetFlag(int flag)
+ {
+ return (GetFlags() & flag) != 0;
+ }
+
+ /// <summary>Sets or clears the specified flag.</summary>
+ /// <remarks>Sets or clears the specified flag.</remarks>
+ /// <param name="flag">
+ /// The flag to set/clear (i.e.,
+ /// <code>NTLMSSP_NEGOTIATE_OEM</code>).
+ /// </param>
+ /// <param name="value">
+ /// Indicates whether to set (<code>true</code>) or
+ /// clear (<code>false</code>) the specified flag.
+ /// </param>
+ public virtual void SetFlag(int flag, bool value)
+ {
+ SetFlags(value ? (GetFlags() | flag) : (GetFlags() & (unchecked((int)(0xffffffff)
+ ) ^ flag)));
+ }
+
+ internal static int ReadULong(byte[] src, int index)
+ {
+ return (src[index] & unchecked(0xff)) | ((src[index + 1] & unchecked(0xff)) << 8) | ((src[index + 2] & unchecked(0xff)) << 16) | ((src[index
+ + 3] & unchecked(0xff)) << 24);
+ }
+
+ internal static int ReadUShort(byte[] src, int index)
+ {
+ return (src[index] & unchecked(0xff)) | ((src[index + 1] & unchecked(0xff)) << 8);
+ }
+
+ internal static byte[] ReadSecurityBuffer(byte[] src, int index)
+ {
+ int length = ReadUShort(src, index);
+ int offset = ReadULong(src, index + 4);
+ byte[] buffer = new byte[length];
+ Array.Copy(src, offset, buffer, 0, length);
+ return buffer;
+ }
+
+ internal static void WriteULong(byte[] dest, int offset, int value)
+ {
+ dest[offset] = unchecked((byte)(value & unchecked(0xff)));
+ dest[offset + 1] = unchecked((byte)(value >> 8 & unchecked(0xff)));
+ dest[offset + 2] = unchecked((byte)(value >> 16 & unchecked(0xff)));
+ dest[offset + 3] = unchecked((byte)(value >> 24 & unchecked(0xff)));
+ }
+
+ internal static void WriteUShort(byte[] dest, int offset, int value)
+ {
+ dest[offset] = unchecked((byte)(value & unchecked(0xff)));
+ dest[offset + 1] = unchecked((byte)(value >> 8 & unchecked(0xff)));
+ }
+
+ internal static void WriteSecurityBuffer(byte[] dest, int offset, int bodyOffset,
+ byte[] src)
+ {
+ int length = (src != null) ? src.Length : 0;
+ if (length == 0)
+ {
+ return;
+ }
+ WriteUShort(dest, offset, length);
+ WriteUShort(dest, offset + 2, length);
+ WriteULong(dest, offset + 4, bodyOffset);
+ Array.Copy(src, 0, dest, bodyOffset, length);
+ }
+
+ internal static string GetOemEncoding()
+ {
+ return OemEncoding;
+ }
+
+ /// <summary>Returns the raw byte representation of this message.</summary>
+ /// <remarks>Returns the raw byte representation of this message.</remarks>
+ /// <returns>A <code>byte[]</code> containing the raw message material.</returns>
+ public abstract byte[] ToByteArray();
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs
new file mode 100644
index 0000000000..afcf5ec7e7
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs
@@ -0,0 +1,249 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.IO;
+using SharpCifs.Netbios;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Ntlmssp
+{
+ /// <summary>Represents an NTLMSSP Type-1 message.</summary>
+ /// <remarks>Represents an NTLMSSP Type-1 message.</remarks>
+ public class Type1Message : NtlmMessage
+ {
+ private static readonly int DefaultFlags;
+
+ private static readonly string DefaultDomain;
+
+ private static readonly string DefaultWorkstation;
+
+ private string _suppliedDomain;
+
+ private string _suppliedWorkstation;
+
+ static Type1Message()
+ {
+ DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode"
+ , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem);
+ DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null);
+ string defaultWorkstation = null;
+ try
+ {
+ defaultWorkstation = NbtAddress.GetLocalHost().GetHostName();
+ }
+ catch (UnknownHostException)
+ {
+ }
+ DefaultWorkstation = defaultWorkstation;
+ }
+
+ /// <summary>
+ /// Creates a Type-1 message using default values from the current
+ /// environment.
+ /// </summary>
+ /// <remarks>
+ /// Creates a Type-1 message using default values from the current
+ /// environment.
+ /// </remarks>
+ public Type1Message() : this(GetDefaultFlags(), GetDefaultDomain(), GetDefaultWorkstation
+ ())
+ {
+ }
+
+ /// <summary>Creates a Type-1 message with the specified parameters.</summary>
+ /// <remarks>Creates a Type-1 message with the specified parameters.</remarks>
+ /// <param name="flags">The flags to apply to this message.</param>
+ /// <param name="suppliedDomain">The supplied authentication domain.</param>
+ /// <param name="suppliedWorkstation">The supplied workstation name.</param>
+ public Type1Message(int flags, string suppliedDomain, string suppliedWorkstation)
+ {
+ SetFlags(GetDefaultFlags() | flags);
+ SetSuppliedDomain(suppliedDomain);
+ if (suppliedWorkstation == null)
+ {
+ suppliedWorkstation = GetDefaultWorkstation();
+ }
+ SetSuppliedWorkstation(suppliedWorkstation);
+ }
+
+ /// <summary>Creates a Type-1 message using the given raw Type-1 material.</summary>
+ /// <remarks>Creates a Type-1 message using the given raw Type-1 material.</remarks>
+ /// <param name="material">The raw Type-1 material used to construct this message.</param>
+ /// <exception cref="System.IO.IOException">If an error occurs while parsing the material.
+ /// </exception>
+ public Type1Message(byte[] material)
+ {
+ Parse(material);
+ }
+
+ /// <summary>Returns the supplied authentication domain.</summary>
+ /// <remarks>Returns the supplied authentication domain.</remarks>
+ /// <returns>A <code>String</code> containing the supplied domain.</returns>
+ public virtual string GetSuppliedDomain()
+ {
+ return _suppliedDomain;
+ }
+
+ /// <summary>Sets the supplied authentication domain for this message.</summary>
+ /// <remarks>Sets the supplied authentication domain for this message.</remarks>
+ /// <param name="suppliedDomain">The supplied domain for this message.</param>
+ public virtual void SetSuppliedDomain(string suppliedDomain)
+ {
+ this._suppliedDomain = suppliedDomain;
+ }
+
+ /// <summary>Returns the supplied workstation name.</summary>
+ /// <remarks>Returns the supplied workstation name.</remarks>
+ /// <returns>A <code>String</code> containing the supplied workstation name.</returns>
+ public virtual string GetSuppliedWorkstation()
+ {
+ return _suppliedWorkstation;
+ }
+
+ /// <summary>Sets the supplied workstation name for this message.</summary>
+ /// <remarks>Sets the supplied workstation name for this message.</remarks>
+ /// <param name="suppliedWorkstation">The supplied workstation for this message.</param>
+ public virtual void SetSuppliedWorkstation(string suppliedWorkstation)
+ {
+ this._suppliedWorkstation = suppliedWorkstation;
+ }
+
+ public override byte[] ToByteArray()
+ {
+ try
+ {
+ string suppliedDomain = GetSuppliedDomain();
+ string suppliedWorkstation = GetSuppliedWorkstation();
+ int flags = GetFlags();
+ bool hostInfo = false;
+ byte[] domain = new byte[0];
+ if (!string.IsNullOrEmpty(suppliedDomain))
+ {
+ hostInfo = true;
+ flags |= NtlmsspNegotiateOemDomainSupplied;
+ domain = Runtime.GetBytesForString(suppliedDomain.ToUpper(), GetOemEncoding
+ ());
+ }
+ else
+ {
+ flags &= (NtlmsspNegotiateOemDomainSupplied ^ unchecked((int)(0xffffffff)));
+ }
+ byte[] workstation = new byte[0];
+ if (!string.IsNullOrEmpty(suppliedWorkstation))
+ {
+ hostInfo = true;
+ flags |= NtlmsspNegotiateOemWorkstationSupplied;
+ workstation = Runtime.GetBytesForString(suppliedWorkstation.ToUpper(), GetOemEncoding
+ ());
+ }
+ else
+ {
+ flags &= (NtlmsspNegotiateOemWorkstationSupplied ^ unchecked((int)(0xffffffff
+ )));
+ }
+ byte[] type1 = new byte[hostInfo ? (32 + domain.Length + workstation.Length) : 16
+ ];
+ Array.Copy(NtlmsspSignature, 0, type1, 0, 8);
+ WriteULong(type1, 8, 1);
+ WriteULong(type1, 12, flags);
+ if (hostInfo)
+ {
+ WriteSecurityBuffer(type1, 16, 32, domain);
+ WriteSecurityBuffer(type1, 24, 32 + domain.Length, workstation);
+ }
+ return type1;
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidOperationException(ex.Message);
+ }
+ }
+
+ public override string ToString()
+ {
+ string suppliedDomain = GetSuppliedDomain();
+ string suppliedWorkstation = GetSuppliedWorkstation();
+ return "Type1Message[suppliedDomain=" + (suppliedDomain ?? "null"
+ ) + ",suppliedWorkstation=" + (suppliedWorkstation ?? "null"
+ ) + ",flags=0x" + Hexdump.ToHexString(GetFlags(), 8) + "]";
+ }
+
+ /// <summary>
+ /// Returns the default flags for a generic Type-1 message in the
+ /// current environment.
+ /// </summary>
+ /// <remarks>
+ /// Returns the default flags for a generic Type-1 message in the
+ /// current environment.
+ /// </remarks>
+ /// <returns>An <code>int</code> containing the default flags.</returns>
+ public static int GetDefaultFlags()
+ {
+ return DefaultFlags;
+ }
+
+ /// <summary>Returns the default domain from the current environment.</summary>
+ /// <remarks>Returns the default domain from the current environment.</remarks>
+ /// <returns>A <code>String</code> containing the default domain.</returns>
+ public static string GetDefaultDomain()
+ {
+ return DefaultDomain;
+ }
+
+ /// <summary>Returns the default workstation from the current environment.</summary>
+ /// <remarks>Returns the default workstation from the current environment.</remarks>
+ /// <returns>A <code>String</code> containing the default workstation.</returns>
+ public static string GetDefaultWorkstation()
+ {
+ return DefaultWorkstation;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ private void Parse(byte[] material)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (material[i] != NtlmsspSignature[i])
+ {
+ throw new IOException("Not an NTLMSSP message.");
+ }
+ }
+ if (ReadULong(material, 8) != 1)
+ {
+ throw new IOException("Not a Type 1 message.");
+ }
+ int flags = ReadULong(material, 12);
+ string suppliedDomain = null;
+ if ((flags & NtlmsspNegotiateOemDomainSupplied) != 0)
+ {
+ byte[] domain = ReadSecurityBuffer(material, 16);
+ suppliedDomain = Runtime.GetStringForBytes(domain, GetOemEncoding());
+ }
+ string suppliedWorkstation = null;
+ if ((flags & NtlmsspNegotiateOemWorkstationSupplied) != 0)
+ {
+ byte[] workstation = ReadSecurityBuffer(material, 24);
+ suppliedWorkstation = Runtime.GetStringForBytes(workstation, GetOemEncoding
+ ());
+ }
+ SetFlags(flags);
+ SetSuppliedDomain(suppliedDomain);
+ SetSuppliedWorkstation(suppliedWorkstation);
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs
new file mode 100644
index 0000000000..104e5b0fdf
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs
@@ -0,0 +1,438 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.IO;
+using SharpCifs.Netbios;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Ntlmssp
+{
+ /// <summary>Represents an NTLMSSP Type-2 message.</summary>
+ /// <remarks>Represents an NTLMSSP Type-2 message.</remarks>
+ public class Type2Message : NtlmMessage
+ {
+ private static readonly int DefaultFlags;
+
+ private static readonly string DefaultDomain;
+
+ private static readonly byte[] DefaultTargetInformation;
+
+ private byte[] _challenge;
+
+ private string _target;
+
+ private byte[] _context;
+
+ private byte[] _targetInformation;
+
+ static Type2Message()
+ {
+ DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode"
+ , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem);
+ DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null);
+ byte[] domain = new byte[0];
+ if (DefaultDomain != null)
+ {
+ try
+ {
+ domain = Runtime.GetBytesForString(DefaultDomain, UniEncoding);
+ }
+ catch (IOException)
+ {
+ }
+ }
+ int domainLength = domain.Length;
+ byte[] server = new byte[0];
+ try
+ {
+ string host = NbtAddress.GetLocalHost().GetHostName();
+ if (host != null)
+ {
+ try
+ {
+ server = Runtime.GetBytesForString(host, UniEncoding);
+ }
+ catch (IOException)
+ {
+ }
+ }
+ }
+ catch (UnknownHostException)
+ {
+ }
+ int serverLength = server.Length;
+ byte[] targetInfo = new byte[(domainLength > 0 ? domainLength + 4 : 0) + (serverLength
+ > 0 ? serverLength + 4 : 0) + 4];
+ int offset = 0;
+ if (domainLength > 0)
+ {
+ WriteUShort(targetInfo, offset, 2);
+ offset += 2;
+ WriteUShort(targetInfo, offset, domainLength);
+ offset += 2;
+ Array.Copy(domain, 0, targetInfo, offset, domainLength);
+ offset += domainLength;
+ }
+ if (serverLength > 0)
+ {
+ WriteUShort(targetInfo, offset, 1);
+ offset += 2;
+ WriteUShort(targetInfo, offset, serverLength);
+ offset += 2;
+ Array.Copy(server, 0, targetInfo, offset, serverLength);
+ }
+ DefaultTargetInformation = targetInfo;
+ }
+
+ /// <summary>
+ /// Creates a Type-2 message using default values from the current
+ /// environment.
+ /// </summary>
+ /// <remarks>
+ /// Creates a Type-2 message using default values from the current
+ /// environment.
+ /// </remarks>
+ public Type2Message() : this(GetDefaultFlags(), null, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates a Type-2 message in response to the given Type-1 message
+ /// using default values from the current environment.
+ /// </summary>
+ /// <remarks>
+ /// Creates a Type-2 message in response to the given Type-1 message
+ /// using default values from the current environment.
+ /// </remarks>
+ /// <param name="type1">The Type-1 message which this represents a response to.</param>
+ public Type2Message(Type1Message type1) : this(type1, null, null)
+ {
+ }
+
+ /// <summary>Creates a Type-2 message in response to the given Type-1 message.</summary>
+ /// <remarks>Creates a Type-2 message in response to the given Type-1 message.</remarks>
+ /// <param name="type1">The Type-1 message which this represents a response to.</param>
+ /// <param name="challenge">The challenge from the domain controller/server.</param>
+ /// <param name="target">The authentication target.</param>
+ public Type2Message(Type1Message type1, byte[] challenge, string target) : this(GetDefaultFlags
+ (type1), challenge, (type1 != null && target == null && type1.GetFlag(NtlmsspRequestTarget
+ )) ? GetDefaultDomain() : target)
+ {
+ }
+
+ /// <summary>Creates a Type-2 message with the specified parameters.</summary>
+ /// <remarks>Creates a Type-2 message with the specified parameters.</remarks>
+ /// <param name="flags">The flags to apply to this message.</param>
+ /// <param name="challenge">The challenge from the domain controller/server.</param>
+ /// <param name="target">The authentication target.</param>
+ public Type2Message(int flags, byte[] challenge, string target)
+ {
+ SetFlags(flags);
+ SetChallenge(challenge);
+ SetTarget(target);
+ if (target != null)
+ {
+ SetTargetInformation(GetDefaultTargetInformation());
+ }
+ }
+
+ /// <summary>Creates a Type-2 message using the given raw Type-2 material.</summary>
+ /// <remarks>Creates a Type-2 message using the given raw Type-2 material.</remarks>
+ /// <param name="material">The raw Type-2 material used to construct this message.</param>
+ /// <exception cref="System.IO.IOException">If an error occurs while parsing the material.
+ /// </exception>
+ public Type2Message(byte[] material)
+ {
+ Parse(material);
+ }
+
+ /// <summary>Returns the challenge for this message.</summary>
+ /// <remarks>Returns the challenge for this message.</remarks>
+ /// <returns>A <code>byte[]</code> containing the challenge.</returns>
+ public virtual byte[] GetChallenge()
+ {
+ return _challenge;
+ }
+
+ /// <summary>Sets the challenge for this message.</summary>
+ /// <remarks>Sets the challenge for this message.</remarks>
+ /// <param name="challenge">The challenge from the domain controller/server.</param>
+ public virtual void SetChallenge(byte[] challenge)
+ {
+ this._challenge = challenge;
+ }
+
+ /// <summary>Returns the authentication target.</summary>
+ /// <remarks>Returns the authentication target.</remarks>
+ /// <returns>A <code>String</code> containing the authentication target.</returns>
+ public virtual string GetTarget()
+ {
+ return _target;
+ }
+
+ /// <summary>Sets the authentication target.</summary>
+ /// <remarks>Sets the authentication target.</remarks>
+ /// <param name="target">The authentication target.</param>
+ public virtual void SetTarget(string target)
+ {
+ this._target = target;
+ }
+
+ /// <summary>Returns the target information block.</summary>
+ /// <remarks>Returns the target information block.</remarks>
+ /// <returns>
+ /// A <code>byte[]</code> containing the target information block.
+ /// The target information block is used by the client to create an
+ /// NTLMv2 response.
+ /// </returns>
+ public virtual byte[] GetTargetInformation()
+ {
+ return _targetInformation;
+ }
+
+ /// <summary>Sets the target information block.</summary>
+ /// <remarks>
+ /// Sets the target information block.
+ /// The target information block is used by the client to create
+ /// an NTLMv2 response.
+ /// </remarks>
+ /// <param name="targetInformation">The target information block.</param>
+ public virtual void SetTargetInformation(byte[] targetInformation)
+ {
+ this._targetInformation = targetInformation;
+ }
+
+ /// <summary>Returns the local security context.</summary>
+ /// <remarks>Returns the local security context.</remarks>
+ /// <returns>
+ /// A <code>byte[]</code> containing the local security
+ /// context. This is used by the client to negotiate local
+ /// authentication.
+ /// </returns>
+ public virtual byte[] GetContext()
+ {
+ return _context;
+ }
+
+ /// <summary>Sets the local security context.</summary>
+ /// <remarks>
+ /// Sets the local security context. This is used by the client
+ /// to negotiate local authentication.
+ /// </remarks>
+ /// <param name="context">The local security context.</param>
+ public virtual void SetContext(byte[] context)
+ {
+ this._context = context;
+ }
+
+ public override byte[] ToByteArray()
+ {
+ try
+ {
+ string targetName = GetTarget();
+ byte[] challenge = GetChallenge();
+ byte[] context = GetContext();
+ byte[] targetInformation = GetTargetInformation();
+ int flags = GetFlags();
+ byte[] target = new byte[0];
+ if ((flags & NtlmsspRequestTarget) != 0)
+ {
+ if (!string.IsNullOrEmpty(targetName))
+ {
+ target = (flags & NtlmsspNegotiateUnicode) != 0 ? Runtime.GetBytesForString
+ (targetName, UniEncoding) : Runtime.GetBytesForString(targetName.ToUpper
+ (), GetOemEncoding());
+ }
+ else
+ {
+ flags &= (unchecked((int)(0xffffffff)) ^ NtlmsspRequestTarget);
+ }
+ }
+ if (targetInformation != null)
+ {
+ flags |= NtlmsspNegotiateTargetInfo;
+ // empty context is needed for padding when t.i. is supplied.
+ if (context == null)
+ {
+ context = new byte[8];
+ }
+ }
+ int data = 32;
+ if (context != null)
+ {
+ data += 8;
+ }
+ if (targetInformation != null)
+ {
+ data += 8;
+ }
+ byte[] type2 = new byte[data + target.Length + (targetInformation != null ? targetInformation
+ .Length : 0)];
+ Array.Copy(NtlmsspSignature, 0, type2, 0, 8);
+ WriteULong(type2, 8, 2);
+ WriteSecurityBuffer(type2, 12, data, target);
+ WriteULong(type2, 20, flags);
+ Array.Copy(challenge ?? new byte[8], 0, type2, 24, 8);
+ if (context != null)
+ {
+ Array.Copy(context, 0, type2, 32, 8);
+ }
+ if (targetInformation != null)
+ {
+ WriteSecurityBuffer(type2, 40, data + target.Length, targetInformation);
+ }
+ return type2;
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidOperationException(ex.Message);
+ }
+ }
+
+ public override string ToString()
+ {
+ string target = GetTarget();
+ byte[] challenge = GetChallenge();
+ byte[] context = GetContext();
+ byte[] targetInformation = GetTargetInformation();
+ return "Type2Message[target=" + target + ",challenge=" + (challenge == null ? "null"
+ : "<" + challenge.Length + " bytes>") + ",context=" + (context == null ? "null"
+ : "<" + context.Length + " bytes>") + ",targetInformation=" + (targetInformation
+ == null ? "null" : "<" + targetInformation.Length + " bytes>") + ",flags=0x" +
+ Hexdump.ToHexString(GetFlags(), 8) + "]";
+ }
+
+ /// <summary>
+ /// Returns the default flags for a generic Type-2 message in the
+ /// current environment.
+ /// </summary>
+ /// <remarks>
+ /// Returns the default flags for a generic Type-2 message in the
+ /// current environment.
+ /// </remarks>
+ /// <returns>An <code>int</code> containing the default flags.</returns>
+ public static int GetDefaultFlags()
+ {
+ return DefaultFlags;
+ }
+
+ /// <summary>
+ /// Returns the default flags for a Type-2 message created in response
+ /// to the given Type-1 message in the current environment.
+ /// </summary>
+ /// <remarks>
+ /// Returns the default flags for a Type-2 message created in response
+ /// to the given Type-1 message in the current environment.
+ /// </remarks>
+ /// <returns>An <code>int</code> containing the default flags.</returns>
+ public static int GetDefaultFlags(Type1Message type1)
+ {
+ if (type1 == null)
+ {
+ return DefaultFlags;
+ }
+ int flags = NtlmsspNegotiateNtlm;
+ int type1Flags = type1.GetFlags();
+ flags |= ((type1Flags & NtlmsspNegotiateUnicode) != 0) ? NtlmsspNegotiateUnicode
+ : NtlmsspNegotiateOem;
+ if ((type1Flags & NtlmsspRequestTarget) != 0)
+ {
+ string domain = GetDefaultDomain();
+ if (domain != null)
+ {
+ flags |= NtlmsspRequestTarget | NtlmsspTargetTypeDomain;
+ }
+ }
+ return flags;
+ }
+
+ /// <summary>Returns the default domain from the current environment.</summary>
+ /// <remarks>Returns the default domain from the current environment.</remarks>
+ /// <returns>A <code>String</code> containing the domain.</returns>
+ public static string GetDefaultDomain()
+ {
+ return DefaultDomain;
+ }
+
+ public static byte[] GetDefaultTargetInformation()
+ {
+ return DefaultTargetInformation;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ private void Parse(byte[] material)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (material[i] != NtlmsspSignature[i])
+ {
+ throw new IOException("Not an NTLMSSP message.");
+ }
+ }
+ if (ReadULong(material, 8) != 2)
+ {
+ throw new IOException("Not a Type 2 message.");
+ }
+ int flags = ReadULong(material, 20);
+ SetFlags(flags);
+ string target = null;
+ byte[] bytes = ReadSecurityBuffer(material, 12);
+ if (bytes.Length != 0)
+ {
+ target = Runtime.GetStringForBytes(bytes, ((flags & NtlmsspNegotiateUnicode
+ ) != 0) ? UniEncoding : GetOemEncoding());
+ }
+ SetTarget(target);
+ for (int i1 = 24; i1 < 32; i1++)
+ {
+ if (material[i1] != 0)
+ {
+ byte[] challenge = new byte[8];
+ Array.Copy(material, 24, challenge, 0, 8);
+ SetChallenge(challenge);
+ break;
+ }
+ }
+ int offset = ReadULong(material, 16);
+ // offset of targetname start
+ if (offset == 32 || material.Length == 32)
+ {
+ return;
+ }
+ for (int i2 = 32; i2 < 40; i2++)
+ {
+ if (material[i2] != 0)
+ {
+ byte[] context = new byte[8];
+ Array.Copy(material, 32, context, 0, 8);
+ SetContext(context);
+ break;
+ }
+ }
+ if (offset == 40 || material.Length == 40)
+ {
+ return;
+ }
+ bytes = ReadSecurityBuffer(material, 40);
+ if (bytes.Length != 0)
+ {
+ SetTargetInformation(bytes);
+ }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs
new file mode 100644
index 0000000000..9a2a37f3cf
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs
@@ -0,0 +1,677 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.IO;
+using SharpCifs.Netbios;
+using SharpCifs.Smb;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Ntlmssp
+{
+ /// <summary>Represents an NTLMSSP Type-3 message.</summary>
+ /// <remarks>Represents an NTLMSSP Type-3 message.</remarks>
+ public class Type3Message : NtlmMessage
+ {
+ internal const long MillisecondsBetween1970And1601 = 11644473600000L;
+
+ private static readonly int DefaultFlags;
+
+ private static readonly string DefaultDomain;
+
+ private static readonly string DefaultUser;
+
+ private static readonly string DefaultPassword;
+
+ private static readonly string DefaultWorkstation;
+
+ private static readonly int LmCompatibility;
+
+ //private static readonly SecureRandom RANDOM = new SecureRandom();
+
+ private byte[] _lmResponse;
+
+ private byte[] _ntResponse;
+
+ private string _domain;
+
+ private string _user;
+
+ private string _workstation;
+
+ private byte[] _masterKey;
+
+ private byte[] _sessionKey;
+
+ static Type3Message()
+ {
+ DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode"
+ , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem);
+ DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null);
+ DefaultUser = Config.GetProperty("jcifs.smb.client.username", null);
+ DefaultPassword = Config.GetProperty("jcifs.smb.client.password", null);
+ string defaultWorkstation = null;
+ try
+ {
+ defaultWorkstation = NbtAddress.GetLocalHost().GetHostName();
+ }
+ catch (UnknownHostException)
+ {
+ }
+ DefaultWorkstation = defaultWorkstation;
+ LmCompatibility = Config.GetInt("jcifs.smb.lmCompatibility", 3);
+ }
+
+ /// <summary>
+ /// Creates a Type-3 message using default values from the current
+ /// environment.
+ /// </summary>
+ /// <remarks>
+ /// Creates a Type-3 message using default values from the current
+ /// environment.
+ /// </remarks>
+ public Type3Message()
+ {
+ SetFlags(GetDefaultFlags());
+ SetDomain(GetDefaultDomain());
+ SetUser(GetDefaultUser());
+ SetWorkstation(GetDefaultWorkstation());
+ }
+
+ /// <summary>
+ /// Creates a Type-3 message in response to the given Type-2 message
+ /// using default values from the current environment.
+ /// </summary>
+ /// <remarks>
+ /// Creates a Type-3 message in response to the given Type-2 message
+ /// using default values from the current environment.
+ /// </remarks>
+ /// <param name="type2">The Type-2 message which this represents a response to.</param>
+ public Type3Message(Type2Message type2)
+ {
+ SetFlags(GetDefaultFlags(type2));
+ SetWorkstation(GetDefaultWorkstation());
+ string domain = GetDefaultDomain();
+ SetDomain(domain);
+ string user = GetDefaultUser();
+ SetUser(user);
+ string password = GetDefaultPassword();
+ switch (LmCompatibility)
+ {
+ case 0:
+ case 1:
+ {
+ SetLmResponse(GetLMResponse(type2, password));
+ SetNtResponse(GetNTResponse(type2, password));
+ break;
+ }
+
+ case 2:
+ {
+ byte[] nt = GetNTResponse(type2, password);
+ SetLmResponse(nt);
+ SetNtResponse(nt);
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ byte[] clientChallenge = new byte[8];
+ //RANDOM.NextBytes(clientChallenge);
+ SetLmResponse(GetLMv2Response(type2, domain, user, password, clientChallenge));
+ break;
+ }
+
+ default:
+ {
+ SetLmResponse(GetLMResponse(type2, password));
+ SetNtResponse(GetNTResponse(type2, password));
+ break;
+ }
+ }
+ }
+
+ /// <summary>Creates a Type-3 message in response to the given Type-2 message.</summary>
+ /// <remarks>Creates a Type-3 message in response to the given Type-2 message.</remarks>
+ /// <param name="type2">The Type-2 message which this represents a response to.</param>
+ /// <param name="password">The password to use when constructing the response.</param>
+ /// <param name="domain">The domain in which the user has an account.</param>
+ /// <param name="user">The username for the authenticating user.</param>
+ /// <param name="workstation">
+ /// The workstation from which authentication is
+ /// taking place.
+ /// </param>
+ public Type3Message(Type2Message type2, string password, string domain, string user
+ , string workstation, int flags)
+ {
+ SetFlags(flags | GetDefaultFlags(type2));
+ if (workstation == null)
+ {
+ workstation = GetDefaultWorkstation();
+ }
+ SetWorkstation(workstation);
+ SetDomain(domain);
+ SetUser(user);
+ switch (LmCompatibility)
+ {
+ case 0:
+ case 1:
+ {
+ if ((GetFlags() & NtlmsspNegotiateNtlm2) == 0)
+ {
+ SetLmResponse(GetLMResponse(type2, password));
+ SetNtResponse(GetNTResponse(type2, password));
+ }
+ else
+ {
+ // NTLM2 Session Response
+ byte[] clientChallenge = new byte[24];
+ //RANDOM.NextBytes(clientChallenge);
+ Arrays.Fill(clientChallenge, 8, 24, unchecked((byte)unchecked(0x00)));
+ // NTLMv1 w/ NTLM2 session sec and key exch all been verified with a debug build of smbclient
+ byte[] responseKeyNt = NtlmPasswordAuthentication.NtowFv1(password);
+ byte[] ntlm2Response = NtlmPasswordAuthentication.GetNtlm2Response(responseKeyNt,
+ type2.GetChallenge(), clientChallenge);
+ SetLmResponse(clientChallenge);
+ SetNtResponse(ntlm2Response);
+ if ((GetFlags() & NtlmsspNegotiateSign) == NtlmsspNegotiateSign)
+ {
+ byte[] sessionNonce = new byte[16];
+ Array.Copy(type2.GetChallenge(), 0, sessionNonce, 0, 8);
+ Array.Copy(clientChallenge, 0, sessionNonce, 8, 8);
+ Md4 md4 = new Md4();
+ md4.Update(responseKeyNt);
+ byte[] userSessionKey = md4.Digest();
+ Hmact64 hmac = new Hmact64(userSessionKey);
+ hmac.Update(sessionNonce);
+ byte[] ntlm2SessionKey = hmac.Digest();
+ if ((GetFlags() & NtlmsspNegotiateKeyExch) != 0)
+ {
+ _masterKey = new byte[16];
+ //RANDOM.NextBytes(masterKey);
+ byte[] exchangedKey = new byte[16];
+ Rc4 rc4 = new Rc4(ntlm2SessionKey);
+ rc4.Update(_masterKey, 0, 16, exchangedKey, 0);
+ SetSessionKey(exchangedKey);
+ }
+ else
+ {
+ _masterKey = ntlm2SessionKey;
+ SetSessionKey(_masterKey);
+ }
+ }
+ }
+ break;
+ }
+
+ case 2:
+ {
+ byte[] nt = GetNTResponse(type2, password);
+ SetLmResponse(nt);
+ SetNtResponse(nt);
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ byte[] responseKeyNt1 = NtlmPasswordAuthentication.NtowFv2(domain, user, password
+ );
+ byte[] clientChallenge1 = new byte[8];
+ //RANDOM.NextBytes(clientChallenge_1);
+ SetLmResponse(GetLMv2Response(type2, domain, user, password, clientChallenge1));
+ byte[] clientChallenge2 = new byte[8];
+ //RANDOM.NextBytes(clientChallenge2);
+ SetNtResponse(GetNtlMv2Response(type2, responseKeyNt1, clientChallenge2));
+ if ((GetFlags() & NtlmsspNegotiateSign) == NtlmsspNegotiateSign)
+ {
+ Hmact64 hmac = new Hmact64(responseKeyNt1);
+ hmac.Update(_ntResponse, 0, 16);
+ // only first 16 bytes of ntResponse
+ byte[] userSessionKey = hmac.Digest();
+ if ((GetFlags() & NtlmsspNegotiateKeyExch) != 0)
+ {
+ _masterKey = new byte[16];
+ //RANDOM.NextBytes(masterKey);
+ byte[] exchangedKey = new byte[16];
+ Rc4 rc4 = new Rc4(userSessionKey);
+ rc4.Update(_masterKey, 0, 16, exchangedKey, 0);
+ SetSessionKey(exchangedKey);
+ }
+ else
+ {
+ _masterKey = userSessionKey;
+ SetSessionKey(_masterKey);
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ SetLmResponse(GetLMResponse(type2, password));
+ SetNtResponse(GetNTResponse(type2, password));
+ break;
+ }
+ }
+ }
+
+ /// <summary>Creates a Type-3 message with the specified parameters.</summary>
+ /// <remarks>Creates a Type-3 message with the specified parameters.</remarks>
+ /// <param name="flags">The flags to apply to this message.</param>
+ /// <param name="lmResponse">The LanManager/LMv2 response.</param>
+ /// <param name="ntResponse">The NT/NTLMv2 response.</param>
+ /// <param name="domain">The domain in which the user has an account.</param>
+ /// <param name="user">The username for the authenticating user.</param>
+ /// <param name="workstation">
+ /// The workstation from which authentication is
+ /// taking place.
+ /// </param>
+ public Type3Message(int flags, byte[] lmResponse, byte[] ntResponse, string domain
+ , string user, string workstation)
+ {
+ SetFlags(flags);
+ SetLmResponse(lmResponse);
+ SetNtResponse(ntResponse);
+ SetDomain(domain);
+ SetUser(user);
+ SetWorkstation(workstation);
+ }
+
+ /// <summary>Creates a Type-3 message using the given raw Type-3 material.</summary>
+ /// <remarks>Creates a Type-3 message using the given raw Type-3 material.</remarks>
+ /// <param name="material">The raw Type-3 material used to construct this message.</param>
+ /// <exception cref="System.IO.IOException">If an error occurs while parsing the material.
+ /// </exception>
+ public Type3Message(byte[] material)
+ {
+ Parse(material);
+ }
+
+ /// <summary>Returns the LanManager/LMv2 response.</summary>
+ /// <remarks>Returns the LanManager/LMv2 response.</remarks>
+ /// <returns>A <code>byte[]</code> containing the LanManager response.</returns>
+ public virtual byte[] GetLMResponse()
+ {
+ return _lmResponse;
+ }
+
+ /// <summary>Sets the LanManager/LMv2 response for this message.</summary>
+ /// <remarks>Sets the LanManager/LMv2 response for this message.</remarks>
+ /// <param name="lmResponse">The LanManager response.</param>
+ public virtual void SetLmResponse(byte[] lmResponse)
+ {
+ this._lmResponse = lmResponse;
+ }
+
+ /// <summary>Returns the NT/NTLMv2 response.</summary>
+ /// <remarks>Returns the NT/NTLMv2 response.</remarks>
+ /// <returns>A <code>byte[]</code> containing the NT/NTLMv2 response.</returns>
+ public virtual byte[] GetNTResponse()
+ {
+ return _ntResponse;
+ }
+
+ /// <summary>Sets the NT/NTLMv2 response for this message.</summary>
+ /// <remarks>Sets the NT/NTLMv2 response for this message.</remarks>
+ /// <param name="ntResponse">The NT/NTLMv2 response.</param>
+ public virtual void SetNtResponse(byte[] ntResponse)
+ {
+ this._ntResponse = ntResponse;
+ }
+
+ /// <summary>Returns the domain in which the user has an account.</summary>
+ /// <remarks>Returns the domain in which the user has an account.</remarks>
+ /// <returns>A <code>String</code> containing the domain for the user.</returns>
+ public virtual string GetDomain()
+ {
+ return _domain;
+ }
+
+ /// <summary>Sets the domain for this message.</summary>
+ /// <remarks>Sets the domain for this message.</remarks>
+ /// <param name="domain">The domain.</param>
+ public virtual void SetDomain(string domain)
+ {
+ this._domain = domain;
+ }
+
+ /// <summary>Returns the username for the authenticating user.</summary>
+ /// <remarks>Returns the username for the authenticating user.</remarks>
+ /// <returns>A <code>String</code> containing the user for this message.</returns>
+ public virtual string GetUser()
+ {
+ return _user;
+ }
+
+ /// <summary>Sets the user for this message.</summary>
+ /// <remarks>Sets the user for this message.</remarks>
+ /// <param name="user">The user.</param>
+ public virtual void SetUser(string user)
+ {
+ this._user = user;
+ }
+
+ /// <summary>Returns the workstation from which authentication is being performed.</summary>
+ /// <remarks>Returns the workstation from which authentication is being performed.</remarks>
+ /// <returns>A <code>String</code> containing the workstation.</returns>
+ public virtual string GetWorkstation()
+ {
+ return _workstation;
+ }
+
+ /// <summary>Sets the workstation for this message.</summary>
+ /// <remarks>Sets the workstation for this message.</remarks>
+ /// <param name="workstation">The workstation.</param>
+ public virtual void SetWorkstation(string workstation)
+ {
+ this._workstation = workstation;
+ }
+
+ /// <summary>
+ /// The real session key if the regular session key is actually
+ /// the encrypted version used for key exchange.
+ /// </summary>
+ /// <remarks>
+ /// The real session key if the regular session key is actually
+ /// the encrypted version used for key exchange.
+ /// </remarks>
+ /// <returns>A <code>byte[]</code> containing the session key.</returns>
+ public virtual byte[] GetMasterKey()
+ {
+ return _masterKey;
+ }
+
+ /// <summary>Returns the session key.</summary>
+ /// <remarks>Returns the session key.</remarks>
+ /// <returns>A <code>byte[]</code> containing the session key.</returns>
+ public virtual byte[] GetSessionKey()
+ {
+ return _sessionKey;
+ }
+
+ /// <summary>Sets the session key.</summary>
+ /// <remarks>Sets the session key.</remarks>
+ /// <param name="sessionKey">The session key.</param>
+ public virtual void SetSessionKey(byte[] sessionKey)
+ {
+ this._sessionKey = sessionKey;
+ }
+
+ public override byte[] ToByteArray()
+ {
+ try
+ {
+ int flags = GetFlags();
+ bool unicode = (flags & NtlmsspNegotiateUnicode) != 0;
+ string oem = unicode ? null : GetOemEncoding();
+ string domainName = GetDomain();
+ byte[] domain = null;
+ if (!string.IsNullOrEmpty(domainName))
+ {
+ domain = unicode ? Runtime.GetBytesForString(domainName, UniEncoding) :
+ Runtime.GetBytesForString(domainName, oem);
+ }
+ int domainLength = (domain != null) ? domain.Length : 0;
+ string userName = GetUser();
+ byte[] user = null;
+ if (!string.IsNullOrEmpty(userName))
+ {
+ user = unicode ? Runtime.GetBytesForString(userName, UniEncoding) : Runtime.GetBytesForString
+ (userName.ToUpper(), oem);
+ }
+ int userLength = (user != null) ? user.Length : 0;
+ string workstationName = GetWorkstation();
+ byte[] workstation = null;
+ if (!string.IsNullOrEmpty(workstationName))
+ {
+ workstation = unicode ? Runtime.GetBytesForString(workstationName, UniEncoding
+ ) : Runtime.GetBytesForString(workstationName.ToUpper(), oem);
+ }
+ int workstationLength = (workstation != null) ? workstation.Length : 0;
+ byte[] lmResponse = GetLMResponse();
+ int lmLength = (lmResponse != null) ? lmResponse.Length : 0;
+ byte[] ntResponse = GetNTResponse();
+ int ntLength = (ntResponse != null) ? ntResponse.Length : 0;
+ byte[] sessionKey = GetSessionKey();
+ int keyLength = (sessionKey != null) ? sessionKey.Length : 0;
+ byte[] type3 = new byte[64 + domainLength + userLength + workstationLength + lmLength
+ + ntLength + keyLength];
+ Array.Copy(NtlmsspSignature, 0, type3, 0, 8);
+ WriteULong(type3, 8, 3);
+ int offset = 64;
+ WriteSecurityBuffer(type3, 12, offset, lmResponse);
+ offset += lmLength;
+ WriteSecurityBuffer(type3, 20, offset, ntResponse);
+ offset += ntLength;
+ WriteSecurityBuffer(type3, 28, offset, domain);
+ offset += domainLength;
+ WriteSecurityBuffer(type3, 36, offset, user);
+ offset += userLength;
+ WriteSecurityBuffer(type3, 44, offset, workstation);
+ offset += workstationLength;
+ WriteSecurityBuffer(type3, 52, offset, sessionKey);
+ WriteULong(type3, 60, flags);
+ return type3;
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidOperationException(ex.Message);
+ }
+ }
+
+ public override string ToString()
+ {
+ string user = GetUser();
+ string domain = GetDomain();
+ string workstation = GetWorkstation();
+ byte[] lmResponse = GetLMResponse();
+ byte[] ntResponse = GetNTResponse();
+ byte[] sessionKey = GetSessionKey();
+ return "Type3Message[domain=" + domain + ",user=" + user + ",workstation=" + workstation
+ + ",lmResponse=" + (lmResponse == null ? "null" : "<" + lmResponse.Length + " bytes>"
+ ) + ",ntResponse=" + (ntResponse == null ? "null" : "<" + ntResponse.Length + " bytes>"
+ ) + ",sessionKey=" + (sessionKey == null ? "null" : "<" + sessionKey.Length + " bytes>"
+ ) + ",flags=0x" + Hexdump.ToHexString(GetFlags(), 8) + "]";
+ }
+
+ /// <summary>
+ /// Returns the default flags for a generic Type-3 message in the
+ /// current environment.
+ /// </summary>
+ /// <remarks>
+ /// Returns the default flags for a generic Type-3 message in the
+ /// current environment.
+ /// </remarks>
+ /// <returns>An <code>int</code> containing the default flags.</returns>
+ public static int GetDefaultFlags()
+ {
+ return DefaultFlags;
+ }
+
+ /// <summary>
+ /// Returns the default flags for a Type-3 message created in response
+ /// to the given Type-2 message in the current environment.
+ /// </summary>
+ /// <remarks>
+ /// Returns the default flags for a Type-3 message created in response
+ /// to the given Type-2 message in the current environment.
+ /// </remarks>
+ /// <returns>An <code>int</code> containing the default flags.</returns>
+ public static int GetDefaultFlags(Type2Message type2)
+ {
+ if (type2 == null)
+ {
+ return DefaultFlags;
+ }
+ int flags = NtlmsspNegotiateNtlm;
+ flags |= ((type2.GetFlags() & NtlmsspNegotiateUnicode) != 0) ? NtlmsspNegotiateUnicode
+ : NtlmsspNegotiateOem;
+ return flags;
+ }
+
+ /// <summary>
+ /// Constructs the LanManager response to the given Type-2 message using
+ /// the supplied password.
+ /// </summary>
+ /// <remarks>
+ /// Constructs the LanManager response to the given Type-2 message using
+ /// the supplied password.
+ /// </remarks>
+ /// <param name="type2">The Type-2 message.</param>
+ /// <param name="password">The password.</param>
+ /// <returns>A <code>byte[]</code> containing the LanManager response.</returns>
+ public static byte[] GetLMResponse(Type2Message type2, string password)
+ {
+ if (type2 == null || password == null)
+ {
+ return null;
+ }
+ return NtlmPasswordAuthentication.GetPreNtlmResponse(password, type2.GetChallenge
+ ());
+ }
+
+ public static byte[] GetLMv2Response(Type2Message type2, string domain, string user
+ , string password, byte[] clientChallenge)
+ {
+ if (type2 == null || domain == null || user == null || password == null || clientChallenge
+ == null)
+ {
+ return null;
+ }
+ return NtlmPasswordAuthentication.GetLMv2Response(domain, user, password, type2.GetChallenge
+ (), clientChallenge);
+ }
+
+ public static byte[] GetNtlMv2Response(Type2Message type2, byte[] responseKeyNt,
+ byte[] clientChallenge)
+ {
+ if (type2 == null || responseKeyNt == null || clientChallenge == null)
+ {
+ return null;
+ }
+ long nanos1601 = (Runtime.CurrentTimeMillis() + MillisecondsBetween1970And1601
+ ) * 10000L;
+ return NtlmPasswordAuthentication.GetNtlMv2Response(responseKeyNt, type2.GetChallenge
+ (), clientChallenge, nanos1601, type2.GetTargetInformation());
+ }
+
+ /// <summary>
+ /// Constructs the NT response to the given Type-2 message using
+ /// the supplied password.
+ /// </summary>
+ /// <remarks>
+ /// Constructs the NT response to the given Type-2 message using
+ /// the supplied password.
+ /// </remarks>
+ /// <param name="type2">The Type-2 message.</param>
+ /// <param name="password">The password.</param>
+ /// <returns>A <code>byte[]</code> containing the NT response.</returns>
+ public static byte[] GetNTResponse(Type2Message type2, string password)
+ {
+ if (type2 == null || password == null)
+ {
+ return null;
+ }
+ return NtlmPasswordAuthentication.GetNtlmResponse(password, type2.GetChallenge());
+ }
+
+ /// <summary>Returns the default domain from the current environment.</summary>
+ /// <remarks>Returns the default domain from the current environment.</remarks>
+ /// <returns>The default domain.</returns>
+ public static string GetDefaultDomain()
+ {
+ return DefaultDomain;
+ }
+
+ /// <summary>Returns the default user from the current environment.</summary>
+ /// <remarks>Returns the default user from the current environment.</remarks>
+ /// <returns>The default user.</returns>
+ public static string GetDefaultUser()
+ {
+ return DefaultUser;
+ }
+
+ /// <summary>Returns the default password from the current environment.</summary>
+ /// <remarks>Returns the default password from the current environment.</remarks>
+ /// <returns>The default password.</returns>
+ public static string GetDefaultPassword()
+ {
+ return DefaultPassword;
+ }
+
+ /// <summary>Returns the default workstation from the current environment.</summary>
+ /// <remarks>Returns the default workstation from the current environment.</remarks>
+ /// <returns>The default workstation.</returns>
+ public static string GetDefaultWorkstation()
+ {
+ return DefaultWorkstation;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ private void Parse(byte[] material)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (material[i] != NtlmsspSignature[i])
+ {
+ throw new IOException("Not an NTLMSSP message.");
+ }
+ }
+ if (ReadULong(material, 8) != 3)
+ {
+ throw new IOException("Not a Type 3 message.");
+ }
+ byte[] lmResponse = ReadSecurityBuffer(material, 12);
+ int lmResponseOffset = ReadULong(material, 16);
+ byte[] ntResponse = ReadSecurityBuffer(material, 20);
+ int ntResponseOffset = ReadULong(material, 24);
+ byte[] domain = ReadSecurityBuffer(material, 28);
+ int domainOffset = ReadULong(material, 32);
+ byte[] user = ReadSecurityBuffer(material, 36);
+ int userOffset = ReadULong(material, 40);
+ byte[] workstation = ReadSecurityBuffer(material, 44);
+ int workstationOffset = ReadULong(material, 48);
+ int flags;
+ string charset;
+ byte[] _sessionKey = null;
+ if (lmResponseOffset == 52 || ntResponseOffset == 52 || domainOffset == 52 || userOffset
+ == 52 || workstationOffset == 52)
+ {
+ flags = NtlmsspNegotiateNtlm | NtlmsspNegotiateOem;
+ charset = GetOemEncoding();
+ }
+ else
+ {
+ _sessionKey = ReadSecurityBuffer(material, 52);
+ flags = ReadULong(material, 60);
+ charset = ((flags & NtlmsspNegotiateUnicode) != 0) ? UniEncoding : GetOemEncoding
+ ();
+ }
+ SetSessionKey(_sessionKey);
+ SetFlags(flags);
+ SetLmResponse(lmResponse);
+ SetNtResponse(ntResponse);
+ SetDomain(Runtime.GetStringForBytes(domain, charset));
+ SetUser(Runtime.GetStringForBytes(user, charset));
+ SetWorkstation(Runtime.GetStringForBytes(workstation, charset));
+ }
+ }
+}