2 // Mono.Security.Protocol.Ntlm.Type3Message - Authentication
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
12 // http://www.innovation.ch/java/ntlm.html
13 // b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
14 // http://davenport.sourceforge.net/ntlm.html
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Globalization;
40 namespace Mono.Security.Protocol.Ntlm {
42 public class Type3Message : MessageBase {
44 private byte[] _challenge;
46 private string _domain;
47 private string _username;
48 private string _password;
52 public Type3Message () : base (3)
55 _domain = Environment.UserDomainName;
56 _host = Environment.MachineName;
57 _username = Environment.UserName;
58 Flags = (NtlmFlags) 0x8201;
61 public Type3Message (byte[] message) : base (3)
68 if (_challenge != null)
69 Array.Clear (_challenge, 0, _challenge.Length);
71 Array.Clear (_lm, 0, _lm.Length);
73 Array.Clear (_nt, 0, _nt.Length);
78 public byte[] Challenge {
80 if (_challenge == null)
82 return (byte[]) _challenge.Clone (); }
85 throw new ArgumentNullException ("Challenge");
86 if (value.Length != 8) {
87 string msg = Locale.GetText ("Invalid Challenge Length (should be 8 bytes).");
88 throw new ArgumentException (msg, "Challenge");
90 _challenge = (byte[]) value.Clone ();
94 public string Domain {
95 get { return _domain; }
100 Flags &= ~NtlmFlags.NegotiateDomainSupplied;
102 Flags |= NtlmFlags.NegotiateDomainSupplied;
109 get { return _host; }
114 Flags &= ~NtlmFlags.NegotiateWorkstationSupplied;
116 Flags |= NtlmFlags.NegotiateWorkstationSupplied;
122 public string Password {
123 get { return _password; }
124 set { _password = value; }
127 public string Username {
128 get { return _username; }
129 set { _username = value; }
142 protected override void Decode (byte[] message)
144 base.Decode (message);
146 if (BitConverterLE.ToUInt16 (message, 56) != message.Length) {
147 string msg = Locale.GetText ("Invalid Type3 message length.");
148 throw new ArgumentException (msg, "message");
153 int dom_len = BitConverterLE.ToUInt16 (message, 28);
155 _domain = Encoding.Unicode.GetString (message, dom_off, dom_len);
157 int host_len = BitConverterLE.ToUInt16 (message, 44);
158 int host_off = BitConverterLE.ToUInt16 (message, 48);
159 _host = Encoding.Unicode.GetString (message, host_off, host_len);
161 int user_len = BitConverterLE.ToUInt16 (message, 36);
162 int user_off = BitConverterLE.ToUInt16 (message, 40);
163 _username = Encoding.Unicode.GetString (message, user_off, user_len);
166 int lm_off = BitConverterLE.ToUInt16 (message, 16);
167 Buffer.BlockCopy (message, lm_off, _lm, 0, 24);
170 int nt_off = BitConverterLE.ToUInt16 (message, 24);
171 Buffer.BlockCopy (message, nt_off, _nt, 0, 24);
173 if (message.Length >= 64)
174 Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 60);
177 public override byte[] GetBytes ()
179 byte[] domain = Encoding.Unicode.GetBytes (_domain.ToUpper (CultureInfo.InvariantCulture));
180 byte[] user = Encoding.Unicode.GetBytes (_username);
181 byte[] host = Encoding.Unicode.GetBytes (_host.ToUpper (CultureInfo.InvariantCulture));
183 byte[] data = PrepareMessage (64 + domain.Length + user.Length + host.Length + 24 + 24);
186 short lmresp_off = (short)(64 + domain.Length + user.Length + host.Length);
187 data [12] = (byte) 0x18;
188 data [13] = (byte) 0x00;
189 data [14] = (byte) 0x18;
190 data [15] = (byte) 0x00;
191 data [16] = (byte) lmresp_off;
192 data [17] = (byte)(lmresp_off >> 8);
195 short ntresp_off = (short)(lmresp_off + 24);
196 data [20] = (byte) 0x18;
197 data [21] = (byte) 0x00;
198 data [22] = (byte) 0x18;
199 data [23] = (byte) 0x00;
200 data [24] = (byte) ntresp_off;
201 data [25] = (byte)(ntresp_off >> 8);
204 short dom_len = (short)domain.Length;
206 data [28] = (byte) dom_len;
207 data [29] = (byte)(dom_len >> 8);
208 data [30] = data [28];
209 data [31] = data [29];
210 data [32] = (byte) dom_off;
211 data [33] = (byte)(dom_off >> 8);
214 short uname_len = (short)user.Length;
215 short uname_off = (short)(dom_off + dom_len);
216 data [36] = (byte) uname_len;
217 data [37] = (byte)(uname_len >> 8);
218 data [38] = data [36];
219 data [39] = data [37];
220 data [40] = (byte) uname_off;
221 data [41] = (byte)(uname_off >> 8);
224 short host_len = (short)host.Length;
225 short host_off = (short)(uname_off + uname_len);
226 data [44] = (byte) host_len;
227 data [45] = (byte)(host_len >> 8);
228 data [46] = data [44];
229 data [47] = data [45];
230 data [48] = (byte) host_off;
231 data [49] = (byte)(host_off >> 8);
234 short msg_len = (short)data.Length;
235 data [56] = (byte) msg_len;
236 data [57] = (byte)(msg_len >> 8);
239 data [60] = (byte) Flags;
240 data [61] = (byte)((uint)Flags >> 8);
241 data [62] = (byte)((uint)Flags >> 16);
242 data [63] = (byte)((uint)Flags >> 24);
244 Buffer.BlockCopy (domain, 0, data, dom_off, domain.Length);
245 Buffer.BlockCopy (user, 0, data, uname_off, user.Length);
246 Buffer.BlockCopy (host, 0, data, host_off, host.Length);
248 using (ChallengeResponse ntlm = new ChallengeResponse (_password, _challenge)) {
249 Buffer.BlockCopy (ntlm.LM, 0, data, lmresp_off, 24);
250 Buffer.BlockCopy (ntlm.NT, 0, data, ntresp_off, 24);