2 // Mono.Security.Protocol.Ntlm.Type2Message - Challenge
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
12 // a. NTLM Authentication Scheme for HTTP, Ronald Tschalär
13 // http://www.innovation.ch/java/ntlm.html
14 // b. The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
15 // http://davenport.sourceforge.net/ntlm.html
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System
.Security
.Cryptography
;
41 namespace Mono
.Security
.Protocol
.Ntlm
{
43 public class Type2Message
: MessageBase
{
45 private byte[] _nonce
;
46 private byte[] _context
;
47 private NtlmTargetInformation _target
;
48 private string _target_name
;
50 public Type2Message () : this (NtlmVersion
.Version1
)
54 public Type2Message (NtlmVersion version
) : base (2, version
)
56 _nonce
= new byte [8];
57 RandomNumberGenerator rng
= RandomNumberGenerator
.Create ();
58 rng
.GetBytes (_nonce
);
60 Flags
= (NtlmFlags
) 0x8201;
61 if (Version
!= NtlmVersion
.Version1
) {
62 _context
= new byte [8];
63 _target
= new NtlmTargetInformation ();
67 public Type2Message (byte[] message
) : this (message
, NtlmVersion
.Version1
)
71 public Type2Message (byte[] message
, NtlmVersion version
) : base (2, version
)
73 _nonce
= new byte [8];
80 Array
.Clear (_nonce
, 0, _nonce
.Length
);
85 public byte[] Context
{
86 get { return (byte[]) _context.Clone (); }
89 throw new ArgumentNullException ("Nonce");
90 if (value.Length
!= 8) {
91 string msg
= Locale
.GetText ("Invalid Nonce Length (should be 8 bytes).");
92 throw new ArgumentException (msg
, "Nonce");
94 _context
= (byte[]) value.Clone ();
99 get { return (byte[]) _nonce.Clone (); }
102 throw new ArgumentNullException ("Nonce");
103 if (value.Length
!= 8) {
104 string msg
= Locale
.GetText ("Invalid Nonce Length (should be 8 bytes).");
105 throw new ArgumentException (msg
, "Nonce");
107 _nonce
= (byte[]) value.Clone ();
111 public NtlmTargetInformation Target
{
112 get { return _target; }
115 public string TargetName
{
116 get { return _target_name; }
117 set { _target_name = value; }
122 protected override void Decode (byte[] message
)
124 base.Decode (message
);
126 short targetNameSize
= BitConverterLE
.ToInt16 (message
, 12);
127 int targetNameOffset
= BitConverterLE
.ToInt32 (message
, 16);
129 Flags
= (NtlmFlags
) BitConverterLE
.ToUInt32 (message
, 20);
131 Buffer
.BlockCopy (message
, 24, _nonce
, 0, 8);
133 if (Version
== NtlmVersion
.Version1
)
136 Buffer
.BlockCopy (message
, 32, _context
, 0, 8);
137 short targetInfoSize
= BitConverterLE
.ToInt16 (message
, 40);
138 int targetInfoOffset
= BitConverterLE
.ToInt32 (message
, 44);
140 if (Version
== NtlmVersion
.Version3
)
141 Buffer
.BlockCopy (OSVersion
, 0, message
, 48, OSVersion
.Length
);
143 Encoding enc
= (Flags
& NtlmFlags
.NegotiateUnicode
) != 0 ? Encoding
.Unicode
: Encoding
.UTF8
;
144 if (targetNameSize
> 0)
145 TargetName
= enc
.GetString (message
, targetNameOffset
, targetNameSize
);
147 _target
.Decode (message
, targetInfoOffset
, targetInfoSize
);
150 public override byte[] GetBytes ()
152 byte [] name_bytes
= null, target
= null;
153 short name_len
= 0, target_len
= 0;
154 if (TargetName
!= null) {
155 Encoding enc
= (Flags
& NtlmFlags
.NegotiateUnicode
) != 0 ? Encoding
.Unicode
: Encoding
.UTF8
;
156 name_bytes
= enc
.GetBytes (TargetName
);
157 name_len
= (short) name_bytes
.Length
;
159 if (Version
!= NtlmVersion
.Version1
) {
160 target
= _target
.ToBytes ();
161 target_len
= (short) target
.Length
;
164 uint name_offset
= (uint) (Version
== NtlmVersion
.Version3
? 56 : 40);
166 int size
= (int) name_offset
+
167 (name_len
> 0 ? name_len
+ 8 : 0) +
168 (target_len
> 0 ? target_len
+ 8 : 0);
169 byte[] data
= PrepareMessage (size
);
172 data
[12] = (byte) name_len
;
173 data
[13] = (byte) (name_len
>> 8);
174 data
[14] = data
[12];
175 data
[15] = data
[13];
176 data
[16] = (byte) name_offset
;
177 data
[17] = (byte) (name_offset
>> 8);
178 data
[18] = (byte) (name_offset
>> 16);
179 data
[19] = (byte) (name_offset
>> 24);
182 data
[20] = (byte) Flags
;
183 data
[21] = (byte)((uint)Flags
>> 8);
184 data
[22] = (byte)((uint)Flags
>> 16);
185 data
[23] = (byte)((uint)Flags
>> 24);
187 Buffer
.BlockCopy (_nonce
, 0, data
, 24, _nonce
.Length
);
189 if (Version
== NtlmVersion
.Version1
)
193 Buffer
.BlockCopy (_context
, 0, data
, 32, 8);
195 // target information
196 data
[40] = (byte) target_len
;
197 data
[41] = (byte) (target_len
>> 8);
198 data
[42] = data
[40];
199 data
[43] = data
[41];
200 uint info_offset
= (uint) (name_offset
+ name_bytes
.Length
);
201 data
[44] = (byte) info_offset
;
202 data
[45] = (byte) (info_offset
>> 8);
203 data
[46] = (byte) (info_offset
>> 16);
204 data
[47] = (byte) (info_offset
>> 24);
206 if (Version
== NtlmVersion
.Version3
)
207 Buffer
.BlockCopy (OSVersion
, 0, data
, 48, OSVersion
.Length
);
209 Buffer
.BlockCopy (name_bytes
, 0, data
, (int) name_offset
, name_len
);
210 Buffer
.BlockCopy (target
, 0, data
, (int) info_offset
, target
.Length
);