Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Pouliot <sebastien@ximian.com>2003-12-02 06:38:55 +0300
committerSebastien Pouliot <sebastien@ximian.com>2003-12-02 06:38:55 +0300
commitf5d4134bc9a77dc2ccc6a3708c82f2bdcdf9b8b5 (patch)
tree46684c05ba657739ebaa43c33fc87c86ded80aac /mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm
parent681d87fc108f0df5f9d6701e2a4421927f78d132 (diff)
2003-12-01 Sebastien Pouliot <spouliot@videotron.ca>
* ChallengeResponse.cs: New. Implements the NTLM (v1) Challenge Response. * MessageBase.cs: New. Abstract base class for NTLM messages. * NtlmFlags.cs: New. All known flags for NTLM. * Type1Message.cs: New. Negotiation message. * Type2Message.cs: New. Challenge message. * Type3Message.cs: New. Authentication message. svn path=/trunk/mcs/; revision=20676
Diffstat (limited to 'mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm')
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse.cs161
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChangeLog8
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/MessageBase.cs79
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/NtlmFlags.cs43
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type1Message.cs106
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type2Message.cs93
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type3Message.cs223
7 files changed, 713 insertions, 0 deletions
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse.cs
new file mode 100755
index 00000000000..ec8559228e9
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse.cs
@@ -0,0 +1,161 @@
+
+// Adapted from http://www.innovation.ch/java/ntlm.html
+// http://davenport.sourceforge.net/ntlm.html
+
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+using Mono.Security.Cryptography;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ public class ChallengeResponse : IDisposable {
+
+ static private byte[] magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
+
+ private bool _disposed;
+ private byte[] _challenge;
+ private byte[] _lmpwd;
+ private byte[] _ntpwd;
+
+ // constructors
+
+ public ChallengeResponse ()
+ {
+ _disposed = false;
+ _lmpwd = new byte [21];
+ _ntpwd = new byte [21];
+ }
+
+ public ChallengeResponse (string password, byte[] challenge) : this ()
+ {
+ Password = password;
+ Challenge = challenge;
+ }
+
+ ~ChallengeResponse ()
+ {
+ if (!_disposed)
+ Dispose ();
+ }
+
+ // properties
+
+ public string Password {
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("Password");
+ if (_disposed)
+ throw new ObjectDisposedException ("too late");
+ // create Lan Manager password
+ DES des = DES.Create ();
+ des.Mode = CipherMode.ECB;
+ des.Key = PasswordToKey (value, 0);
+ ICryptoTransform ct = des.CreateEncryptor ();
+ ct.TransformBlock (magic, 0, 8, _lmpwd, 0);
+ des.Key = PasswordToKey (value, 7);
+ ct = des.CreateEncryptor ();
+ ct.TransformBlock (magic, 0, 8, _lmpwd, 8);
+ // create NT password
+ MD4 md4 = MD4.Create ();
+ byte[] hash = md4.ComputeHash (Encoding.Unicode.GetBytes (value));
+ Buffer.BlockCopy (hash, 0, _ntpwd, 0, 16);
+ }
+ }
+
+ public byte[] Challenge {
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("Challenge");
+ if (_disposed)
+ throw new ObjectDisposedException ("too late");
+ // we don't want the caller to modify the value afterward
+ _challenge = (byte[]) value.Clone ();
+ }
+ }
+
+ public byte[] LM {
+ get {
+ if (_disposed)
+ throw new ObjectDisposedException ("too late");
+
+ return GetResponse (_lmpwd);
+ }
+ }
+
+ public byte[] NT {
+ get {
+ if (_disposed)
+ throw new ObjectDisposedException ("too late");
+
+ return GetResponse (_ntpwd);
+ }
+ }
+
+ // IDisposable method
+
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ private void Dispose (bool disposing)
+ {
+ if (!_disposed) {
+ // cleanup our stuff
+ Array.Clear (_lmpwd, 0, _lmpwd.Length);
+ Array.Clear (_ntpwd, 0, _ntpwd.Length);
+ if (_challenge != null)
+ Array.Clear (_challenge, 0, _challenge.Length);
+ _disposed = true;
+ }
+ }
+
+ // private methods
+
+ private byte[] GetResponse (byte[] pwd)
+ {
+ byte[] response = new byte [24];
+ DES des = DES.Create ();
+ des.Mode = CipherMode.ECB;
+ des.Key = PrepareDESKey (pwd, 0);
+ ICryptoTransform ct = des.CreateEncryptor ();
+ ct.TransformBlock (_challenge, 0, 8, response, 0);
+ des.Key = PrepareDESKey (pwd, 7);
+ ct = des.CreateEncryptor ();
+ ct.TransformBlock (_challenge, 0, 8, response, 8);
+ des.Key = PrepareDESKey (pwd, 14);
+ ct = des.CreateEncryptor ();
+ ct.TransformBlock (_challenge, 0, 8, response, 16);
+ return response;
+ }
+
+ private byte[] PrepareDESKey (byte[] key56bits, int position)
+ {
+ // convert to 8 bytes
+ byte[] key = new byte [8];
+ key [0] = key56bits [position];
+ key [1] = (byte) ((key56bits [position] << 7) | (key56bits [position + 1] >> 1));
+ key [2] = (byte) ((key56bits [position + 1] << 6) | (key56bits [position + 2] >> 2));
+ key [3] = (byte) ((key56bits [position + 2] << 5) | (key56bits [position + 3] >> 3));
+ key [4] = (byte) ((key56bits [position + 3] << 4) | (key56bits [position + 4] >> 4));
+ key [5] = (byte) ((key56bits [position + 4] << 3) | (key56bits [position + 5] >> 5));
+ key [6] = (byte) ((key56bits [position + 5] << 2) | (key56bits [position + 6] >> 6));
+ key [7] = (byte) (key56bits [position + 6] << 1);
+ return key;
+ }
+
+ private byte[] PasswordToKey (string password, int position)
+ {
+ byte[] key7 = new byte [7];
+ int len = Math.Min (password.Length - position, 7);
+ Encoding.ASCII.GetBytes (password.ToUpper (), position, len, key7, 0);
+ byte[] key8 = PrepareDESKey (key7, 0);
+ // cleanup intermediate key material
+ Array.Clear (key7, 0, key7.Length);
+ return key8;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChangeLog b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChangeLog
new file mode 100755
index 00000000000..015965bd4e0
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/ChangeLog
@@ -0,0 +1,8 @@
+2003-12-01 Sebastien Pouliot <spouliot@videotron.ca>
+
+ * ChallengeResponse.cs: New. Implements the NTLM (v1) Challenge Response.
+ * MessageBase.cs: New. Abstract base class for NTLM messages.
+ * NtlmFlags.cs: New. All known flags for NTLM.
+ * Type1Message.cs: New. Negotiation message.
+ * Type2Message.cs: New. Challenge message.
+ * Type3Message.cs: New. Authentication message.
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/MessageBase.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/MessageBase.cs
new file mode 100755
index 00000000000..39288c26563
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/MessageBase.cs
@@ -0,0 +1,79 @@
+//
+// Mono.Security.Protocol.Ntlm.MessageBase
+// abstract class for all NTLM messages
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+// References
+// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
+// http://www.innovation.ch/java/ntlm.html
+// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
+// http://davenport.sourceforge.net/ntlm.html
+//
+
+using System;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ public abstract class MessageBase {
+
+ static private byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00 };
+
+ private int _type;
+ private NtlmFlags _flags;
+
+ protected MessageBase (int messageType)
+ {
+ _type = messageType;
+ }
+
+ public NtlmFlags Flags {
+ get { return _flags; }
+ set { _flags = value; }
+ }
+
+ public int Type {
+ get { return _type; }
+ }
+
+ protected byte[] PrepareMessage (int messageSize)
+ {
+ byte[] message = new byte [messageSize];
+ Buffer.BlockCopy (header, 0, message, 0, 8);
+
+ message [ 8] = (byte) _type;
+ message [ 9] = (byte)(_type >> 8);
+ message [10] = (byte)(_type >> 16);
+ message [11] = (byte)(_type >> 24);
+
+ return message;
+ }
+
+ protected virtual void Decode (byte[] message)
+ {
+ if (message == null)
+ throw new ArgumentNullException ("message");
+
+ if (message.Length < 12)
+ throw new ArgumentOutOfRangeException ("message", message.Length, "minimum is 12 bytes");
+
+ if (!CheckHeader (message))
+ throw new ArgumentException ("Invalid Type" + _type + " message");
+ }
+
+
+ protected bool CheckHeader (byte[] message)
+ {
+ for (int i=0; i < header.Length; i++) {
+ if (message [i] != header [i])
+ return false;
+ }
+ return (BitConverter.ToUInt32 (message, 8) == _type);
+ }
+
+ public abstract byte[] GetBytes ();
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/NtlmFlags.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/NtlmFlags.cs
new file mode 100755
index 00000000000..74ed4878157
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/NtlmFlags.cs
@@ -0,0 +1,43 @@
+//
+// Mono.Security.Protocol.Ntlm.NtlmFlags
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+// References
+// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
+// http://www.innovation.ch/java/ntlm.html
+// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
+// http://davenport.sourceforge.net/ntlm.html
+//
+
+using System;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ [Flags]
+ public enum NtlmFlags : uint {
+ // The client sets this flag to indicate that it supports Unicode strings.
+ NegotiateUnicode = 0x00000001,
+ // This is set to indicate that the client supports OEM strings.
+ NegotiateOEM = 0x00000002,
+ // This requests that the server send the authentication target with the Type 2 reply.
+ RequestTarget = 0x00000004,
+ // Indicates that NTLM authentication is supported.
+ NegotiateNTLM = 0x00000200,
+ // When set, the client will send with the message the name of the domain in which the workstation has membership.
+ NegotiateDomainSupplied = 0x00001000,
+ // Indicates that the client is sending its workstation name with the message.
+ NegotiateWorkstationSupplied = 0x00002000,
+ // Indicates that communication between the client and server after authentication should carry a "dummy" signature.
+ NegotiateAlwaysSign = 0x00008000,
+ // Indicates that this client supports the NTLM2 signing and sealing scheme; if negotiated, this can also affect the response calculations.
+ NegotiateNTLM2Key = 0x00080000,
+ // Indicates that this client supports strong (128-bit) encryption.
+ Negotiate128 = 0x20000000,
+ // Indicates that this client supports medium (56-bit) encryption.
+ Negotiate56 = 0x80000000
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type1Message.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type1Message.cs
new file mode 100755
index 00000000000..3376456db17
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type1Message.cs
@@ -0,0 +1,106 @@
+//
+// Mono.Security.Protocol.Ntlm.Type1Message - Negotiation
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+// References
+// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
+// http://www.innovation.ch/java/ntlm.html
+// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
+// http://davenport.sourceforge.net/ntlm.html
+//
+
+using System;
+using System.Text;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ public class Type1Message : MessageBase {
+
+ //static private byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xb2, 0x00, 0x00 };
+
+ private string _host;
+ private string _domain;
+
+ public Type1Message () : base (1)
+ {
+ // default values
+ _domain = Environment.UserDomainName;
+ _host = Environment.MachineName;
+ Flags = (NtlmFlags) 0xb203;
+ }
+
+ public Type1Message (byte[] message) : base (1)
+ {
+ Decode (message);
+ }
+
+ // properties
+
+ public string Domain {
+ get { return _domain; }
+ set { _domain = value; }
+ }
+
+ public string Host {
+ get { return _host; }
+ set { _host = value; }
+ }
+
+ // methods
+
+ protected override void Decode (byte[] message)
+ {
+ base.Decode (message);
+
+ Flags = (NtlmFlags) BitConverter.ToUInt32 (message, 12);
+
+ int dom_len = BitConverter.ToUInt16 (message, 16);
+ int dom_off = BitConverter.ToUInt16 (message, 20);
+ _domain = Encoding.ASCII.GetString (message, dom_off, dom_len);
+
+ int host_len = BitConverter.ToUInt16 (message, 24);
+ _host = Encoding.ASCII.GetString (message, 32, host_len);
+ }
+
+ public override byte[] GetBytes ()
+ {
+ short dom_len = (short) _domain.Length;
+ short host_len = (short) _host.Length;
+
+ byte[] data = PrepareMessage (32 + dom_len + host_len);
+
+ data [12] = (byte) Flags;
+ data [13] = (byte)((uint)Flags >> 8);
+ data [14] = (byte)((uint)Flags >> 16);
+ data [15] = (byte)((uint)Flags >> 24);
+
+ short dom_off = (short)(32 + host_len);
+
+ data [16] = (byte) dom_len;
+ data [17] = (byte)(dom_len >> 8);
+ data [18] = data [16];
+ data [19] = data [17];
+ data [20] = (byte) dom_off;
+ data [21] = (byte)(dom_off >> 8);
+
+ data [24] = (byte) host_len;
+ data [25] = (byte)(host_len >> 8);
+ data [26] = data [24];
+ data [27] = data [25];
+ data [28] = 0x20;
+ data [29] = 0x00;
+
+ byte[] host = Encoding.ASCII.GetBytes (_host.ToUpper ());
+ Buffer.BlockCopy (host, 0, data, 32, host.Length);
+
+ byte[] domain = Encoding.ASCII.GetBytes (_domain.ToUpper ());
+ Buffer.BlockCopy (domain, 0, data, dom_off, domain.Length);
+
+ return data;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type2Message.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type2Message.cs
new file mode 100755
index 00000000000..7e1a513523c
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type2Message.cs
@@ -0,0 +1,93 @@
+//
+// Mono.Security.Protocol.Ntlm.Type2Message - Challenge
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+// References
+// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
+// http://www.innovation.ch/java/ntlm.html
+// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
+// http://davenport.sourceforge.net/ntlm.html
+//
+
+using System;
+using System.Security.Cryptography;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ public class Type2Message : MessageBase {
+
+ private byte[] _nonce;
+ private int _options;
+
+ public Type2Message () : base (2)
+ {
+ _nonce = new byte [8];
+ RandomNumberGenerator rng = RandomNumberGenerator.Create ();
+ rng.GetBytes (_nonce);
+ // default values
+ Flags = (NtlmFlags) 0x8201;
+ }
+
+ public Type2Message (byte[] message) : base (2)
+ {
+ _nonce = new byte [8];
+ Decode (message);
+ }
+
+ ~Type2Message ()
+ {
+ if (_nonce != null)
+ Array.Clear (_nonce, 0, _nonce.Length);
+ }
+
+ // properties
+
+ public byte[] Nonce {
+ get { return (byte[]) _nonce.Clone (); }
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("Nonce");
+ if (value.Length != 8)
+ throw new ArgumentException ("Invalid Nonce Length");
+ _nonce = (byte[]) value.Clone ();
+ }
+ }
+
+ // methods
+
+ private void Decode (byte[] message)
+ {
+ if (message == null)
+ throw new ArgumentNullException ("message");
+
+ if (!CheckHeader (message))
+ throw new ArgumentException ("Invalid Type2 message");
+
+ Flags = (NtlmFlags) BitConverter.ToUInt32 (message, 20);
+
+ Buffer.BlockCopy (message, 24, _nonce, 0, 8);
+ }
+
+ public override byte[] GetBytes ()
+ {
+ byte[] data = PrepareMessage (40);
+
+ // message length
+ short msg_len = (short)data.Length;
+ data [16] = (byte) msg_len;
+ data [17] = (byte)(msg_len >> 8);
+
+ // flags
+ uint f = (uint) Flags;
+ data [20] = (byte) f;
+ data [21] = (byte)(f >> 8);
+
+ Buffer.BlockCopy (_nonce, 0, data, 24, _nonce.Length);
+ return data;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type3Message.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type3Message.cs
new file mode 100755
index 00000000000..972fa5c3513
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm/Type3Message.cs
@@ -0,0 +1,223 @@
+//
+// Mono.Security.Protocol.Ntlm.Type3Message - Authentication
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+// References
+// a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
+// http://www.innovation.ch/java/ntlm.html
+// b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
+// http://davenport.sourceforge.net/ntlm.html
+//
+
+using System;
+using System.Text;
+
+namespace Mono.Security.Protocol.Ntlm {
+
+ public class Type3Message : MessageBase {
+
+ static private byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00 };
+
+ private byte[] _challenge;
+ private string _host;
+ private string _domain;
+ private string _username;
+ private string _password;
+ private byte[] _lm;
+ private byte[] _nt;
+ private int _options;
+
+ public Type3Message () : base (3)
+ {
+ // default values
+ _domain = Environment.UserDomainName;
+ _host = Environment.MachineName;
+ _username = Environment.UserName;
+ _options = 0x8201;
+ }
+
+ public Type3Message (byte[] message) : base (3)
+ {
+ Decode (message);
+ }
+
+ ~Type3Message ()
+ {
+ if (_challenge != null)
+ Array.Clear (_challenge, 0, _challenge.Length);
+ if (_lm != null)
+ Array.Clear (_lm, 0, _lm.Length);
+ if (_nt != null)
+ Array.Clear (_nt, 0, _nt.Length);
+ }
+
+ // properties
+
+ public byte[] Challenge {
+ get {
+ if (_challenge == null)
+ return null;
+ return (byte[]) _challenge.Clone (); }
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("Challenge");
+ if (value.Length != 8)
+ throw new ArgumentException ("Invalid Challenge Length");
+ _challenge = (byte[]) value.Clone ();
+ }
+ }
+
+ public string Domain {
+ get { return _domain; }
+ set { _domain = value; }
+ }
+
+ public string Host {
+ get { return _host; }
+ set { _host = value; }
+ }
+
+ public int Options {
+ get { return _options; }
+ set { _options = value; }
+ }
+
+ public string Password {
+ get { return _password; }
+ set { _password = value; }
+ }
+
+ public string Username {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ public byte[] LM {
+ get { return _lm; }
+ }
+
+ public byte[] NT {
+ get { return _nt; }
+ }
+
+ // methods
+
+ private void Decode (byte[] message)
+ {
+ if (message == null)
+ throw new ArgumentNullException ("message");
+
+ for (int i=0; i < header.Length; i++) {
+ if (message [i] != header [i])
+ throw new ArgumentException ("Invalid Type3 message");
+ }
+
+ if (BitConverter.ToUInt16 (message, 56) != message.Length)
+ throw new ArgumentException ("Invalid Type3 message length");
+
+ _password = null;
+
+ int dom_len = BitConverter.ToUInt16 (message, 28);
+ int dom_off = 64;
+ _domain = Encoding.Unicode.GetString (message, dom_off, dom_len);
+
+ int host_len = BitConverter.ToUInt16 (message, 44);
+ int host_off = BitConverter.ToUInt16 (message, 48);
+ _host = Encoding.Unicode.GetString (message, host_off, host_len);
+
+ int user_len = BitConverter.ToUInt16 (message, 36);
+ int user_off = BitConverter.ToUInt16 (message, 40);
+ _username = Encoding.Unicode.GetString (message, user_off, user_len);
+
+ _options = BitConverter.ToUInt16 (message, 60);
+
+ _lm = new byte [24];
+ int lm_off = BitConverter.ToUInt16 (message, 16);
+ Buffer.BlockCopy (message, lm_off, _lm, 0, 24);
+
+ _nt = new byte [24];
+ int nt_off = BitConverter.ToUInt16 (message, 24);
+ Buffer.BlockCopy (message, nt_off, _nt, 0, 24);
+
+ if (message.Length >= 64)
+ Flags = (NtlmFlags) BitConverter.ToUInt32 (message, 60);
+ }
+
+ public override byte[] GetBytes ()
+ {
+ byte[] domain = Encoding.Unicode.GetBytes (_domain.ToUpper ());
+ byte[] user = Encoding.Unicode.GetBytes (_username);
+ byte[] host = Encoding.Unicode.GetBytes (_host.ToUpper ());
+
+ byte[] data = new byte [64 + domain.Length + user.Length + host.Length + 24 + 24];
+ Buffer.BlockCopy (header, 0, data, 0, header.Length);
+
+ // LM response
+ short lmresp_off = (short)(64 + domain.Length + user.Length + host.Length);
+ data [16] = (byte) lmresp_off;
+ data [17] = (byte)(lmresp_off >> 8);
+
+ // NT response
+ short ntresp_off = (short)(lmresp_off + 24);
+ data [20] = (byte) 0x18;
+ data [21] = (byte) 0x00;
+ data [22] = (byte) 0x18;
+ data [23] = (byte) 0x00;
+ data [24] = (byte) ntresp_off;
+ data [25] = (byte)(ntresp_off >> 8);
+
+ // domain
+ short dom_len = (short)domain.Length;
+ short dom_off = 64;
+ data [28] = (byte) dom_len;
+ data [29] = (byte)(dom_len >> 8);
+ data [30] = data [28];
+ data [31] = data [29];
+ data [32] = (byte) dom_off;
+ data [33] = (byte)(dom_off >> 8);
+
+ // username
+ short uname_len = (short)user.Length;
+ short uname_off = (short)(dom_off + dom_len);
+ data [36] = (byte) uname_len;
+ data [37] = (byte)(uname_len >> 8);
+ data [38] = data [36];
+ data [39] = data [37];
+ data [40] = (byte) uname_off;
+ data [41] = (byte)(uname_off >> 8);
+
+ // host
+ short host_len = (short)host.Length;
+ short host_off = (short)(uname_off + uname_len);
+ data [44] = (byte) host_len;
+ data [45] = (byte)(host_len >> 8);
+ data [46] = data [44];
+ data [47] = data [45];
+ data [48] = (byte) host_off;
+ data [49] = (byte)(host_off >> 8);
+
+ // message length
+ short msg_len = (short)data.Length;
+ data [56] = (byte) msg_len;
+ data [57] = (byte)(msg_len >> 8);
+
+ // options flags
+ data [60] = (byte) _options;
+ data [61] = (byte)(_options >> 8);
+
+ Buffer.BlockCopy (domain, 0, data, dom_off, domain.Length);
+ Buffer.BlockCopy (user, 0, data, uname_off, user.Length);
+ Buffer.BlockCopy (host, 0, data, host_off, host.Length);
+
+ using (ChallengeResponse ntlm = new ChallengeResponse (_password, _challenge)) {
+ Buffer.BlockCopy (ntlm.LM, 0, data, lmresp_off, 24);
+ Buffer.BlockCopy (ntlm.NT, 0, data, ntresp_off, 24);
+ }
+ return data;
+ }
+ }
+}