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; }
96 set { _domain = value; }
100 get { return _host; }
101 set { _host = value; }
104 public string Password
{
105 get { return _password; }
106 set { _password = value; }
109 public string Username
{
110 get { return _username; }
111 set { _username = value; }
124 protected override void Decode (byte[] message
)
126 base.Decode (message
);
128 if (BitConverterLE
.ToUInt16 (message
, 56) != message
.Length
) {
129 string msg
= Locale
.GetText ("Invalid Type3 message length.");
130 throw new ArgumentException (msg
, "message");
135 int dom_len
= BitConverterLE
.ToUInt16 (message
, 28);
137 _domain
= Encoding
.Unicode
.GetString (message
, dom_off
, dom_len
);
139 int host_len
= BitConverterLE
.ToUInt16 (message
, 44);
140 int host_off
= BitConverterLE
.ToUInt16 (message
, 48);
141 _host
= Encoding
.Unicode
.GetString (message
, host_off
, host_len
);
143 int user_len
= BitConverterLE
.ToUInt16 (message
, 36);
144 int user_off
= BitConverterLE
.ToUInt16 (message
, 40);
145 _username
= Encoding
.Unicode
.GetString (message
, user_off
, user_len
);
148 int lm_off
= BitConverterLE
.ToUInt16 (message
, 16);
149 Buffer
.BlockCopy (message
, lm_off
, _lm
, 0, 24);
152 int nt_off
= BitConverterLE
.ToUInt16 (message
, 24);
153 Buffer
.BlockCopy (message
, nt_off
, _nt
, 0, 24);
155 if (message
.Length
>= 64)
156 Flags
= (NtlmFlags
) BitConverterLE
.ToUInt32 (message
, 60);
159 public override byte[] GetBytes ()
161 byte[] domain
= Encoding
.Unicode
.GetBytes (_domain
.ToUpper (CultureInfo
.InvariantCulture
));
162 byte[] user
= Encoding
.Unicode
.GetBytes (_username
);
163 byte[] host
= Encoding
.Unicode
.GetBytes (_host
.ToUpper (CultureInfo
.InvariantCulture
));
165 byte[] data
= PrepareMessage (64 + domain
.Length
+ user
.Length
+ host
.Length
+ 24 + 24);
168 short lmresp_off
= (short)(64 + domain
.Length
+ user
.Length
+ host
.Length
);
169 data
[12] = (byte) 0x18;
170 data
[13] = (byte) 0x00;
171 data
[14] = (byte) 0x18;
172 data
[15] = (byte) 0x00;
173 data
[16] = (byte) lmresp_off
;
174 data
[17] = (byte)(lmresp_off
>> 8);
177 short ntresp_off
= (short)(lmresp_off
+ 24);
178 data
[20] = (byte) 0x18;
179 data
[21] = (byte) 0x00;
180 data
[22] = (byte) 0x18;
181 data
[23] = (byte) 0x00;
182 data
[24] = (byte) ntresp_off
;
183 data
[25] = (byte)(ntresp_off
>> 8);
186 short dom_len
= (short)domain
.Length
;
188 data
[28] = (byte) dom_len
;
189 data
[29] = (byte)(dom_len
>> 8);
190 data
[30] = data
[28];
191 data
[31] = data
[29];
192 data
[32] = (byte) dom_off
;
193 data
[33] = (byte)(dom_off
>> 8);
196 short uname_len
= (short)user
.Length
;
197 short uname_off
= (short)(dom_off
+ dom_len
);
198 data
[36] = (byte) uname_len
;
199 data
[37] = (byte)(uname_len
>> 8);
200 data
[38] = data
[36];
201 data
[39] = data
[37];
202 data
[40] = (byte) uname_off
;
203 data
[41] = (byte)(uname_off
>> 8);
206 short host_len
= (short)host
.Length
;
207 short host_off
= (short)(uname_off
+ uname_len
);
208 data
[44] = (byte) host_len
;
209 data
[45] = (byte)(host_len
>> 8);
210 data
[46] = data
[44];
211 data
[47] = data
[45];
212 data
[48] = (byte) host_off
;
213 data
[49] = (byte)(host_off
>> 8);
216 short msg_len
= (short)data
.Length
;
217 data
[56] = (byte) msg_len
;
218 data
[57] = (byte)(msg_len
>> 8);
221 data
[60] = (byte) Flags
;
222 data
[61] = (byte)((uint)Flags
>> 8);
223 data
[62] = (byte)((uint)Flags
>> 16);
224 data
[63] = (byte)((uint)Flags
>> 24);
226 Buffer
.BlockCopy (domain
, 0, data
, dom_off
, domain
.Length
);
227 Buffer
.BlockCopy (user
, 0, data
, uname_off
, user
.Length
);
228 Buffer
.BlockCopy (host
, 0, data
, host_off
, host
.Length
);
230 using (ChallengeResponse ntlm
= new ChallengeResponse (_password
, _challenge
)) {
231 Buffer
.BlockCopy (ntlm
.LM
, 0, data
, lmresp_off
, 24);
232 Buffer
.BlockCopy (ntlm
.NT
, 0, data
, ntresp_off
, 24);