Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,230 @@
//
// Mono.Security.Protocol.Ntlm.ChallengeResponse
// Implements Challenge Response for NTLM v1
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// (C) 2004 Novell (http://www.novell.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
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using Mono.Security.Cryptography;
namespace Mono.Security.Protocol.Ntlm {
[Obsolete (Type3Message.LegacyAPIWarning)]
#if INSIDE_SYSTEM
internal
#else
public
#endif
class ChallengeResponse : IDisposable {
static private byte[] magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
// This is the pre-encrypted magic value with a null DES key (0xAAD3B435B51404EE)
// Ref: http://packetstormsecurity.nl/Crackers/NT/l0phtcrack/l0phtcrack2.5-readme.html
static private byte[] nullEncMagic = { 0xAA, 0xD3, 0xB4, 0x35, 0xB5, 0x14, 0x04, 0xEE };
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 {
get { return null; }
set {
if (_disposed)
throw new ObjectDisposedException ("too late");
// create Lan Manager password
DES des = DES.Create ();
des.Mode = CipherMode.ECB;
ICryptoTransform ct = null;
// Note: In .NET DES cannot accept a weak key
// this can happen for a null password
if ((value == null) || (value.Length < 1)) {
Buffer.BlockCopy (nullEncMagic, 0, _lmpwd, 0, 8);
}
else {
des.Key = PasswordToKey (value, 0);
ct = des.CreateEncryptor ();
ct.TransformBlock (magic, 0, 8, _lmpwd, 0);
}
// and if a password has less than 8 characters
if ((value == null) || (value.Length < 8)) {
Buffer.BlockCopy (nullEncMagic, 0, _lmpwd, 8, 8);
}
else {
des.Key = PasswordToKey (value, 7);
ct = des.CreateEncryptor ();
ct.TransformBlock (magic, 0, 8, _lmpwd, 8);
}
// create NT password
MD4 md4 = MD4.Create ();
byte[] data = ((value == null) ? (new byte [0]) : (Encoding.Unicode.GetBytes (value)));
byte[] hash = md4.ComputeHash (data);
Buffer.BlockCopy (hash, 0, _ntpwd, 0, 16);
// clean up
Array.Clear (data, 0, data.Length);
Array.Clear (hash, 0, hash.Length);
des.Clear ();
}
}
public byte[] Challenge {
get { return null; }
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 = System.Math.Min (password.Length - position, 7);
Encoding.ASCII.GetBytes (password.ToUpper (CultureInfo.CurrentCulture), position, len, key7, 0);
byte[] key8 = PrepareDESKey (key7, 0);
// cleanup intermediate key material
Array.Clear (key7, 0, key7.Length);
return key8;
}
}
}

View File

@@ -0,0 +1,284 @@
//
// Mono.Security.Protocol.Ntlm.ChallengeResponse
// Implements Challenge Response for NTLM v1 and NTLM v2 Session
//
// Authors:
// Sebastien Pouliot <sebastien@ximian.com>
// Martin Baulig <martin.baulig@xamarin.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// (C) 2004 Novell (http://www.novell.com)
// (C) 2012 Xamarin, Inc. (http://www.xamarin.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
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Net;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using Mono.Security.Cryptography;
namespace Mono.Security.Protocol.Ntlm {
#if INSIDE_SYSTEM
internal
#else
public
#endif
static class ChallengeResponse2 {
static private byte[] magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
// This is the pre-encrypted magic value with a null DES key (0xAAD3B435B51404EE)
// Ref: http://packetstormsecurity.nl/Crackers/NT/l0phtcrack/l0phtcrack2.5-readme.html
static private byte[] nullEncMagic = { 0xAA, 0xD3, 0xB4, 0x35, 0xB5, 0x14, 0x04, 0xEE };
static byte[] Compute_LM (string password, byte[] challenge)
{
var buffer = new byte [21];
// create Lan Manager password
DES des = DES.Create ();
des.Mode = CipherMode.ECB;
ICryptoTransform ct = null;
// Note: In .NET DES cannot accept a weak key
// this can happen for a null password
if ((password == null) || (password.Length < 1)) {
Buffer.BlockCopy (nullEncMagic, 0, buffer, 0, 8);
} else {
des.Key = PasswordToKey (password, 0);
ct = des.CreateEncryptor ();
ct.TransformBlock (magic, 0, 8, buffer, 0);
}
// and if a password has less than 8 characters
if ((password == null) || (password.Length < 8)) {
Buffer.BlockCopy (nullEncMagic, 0, buffer, 8, 8);
} else {
des.Key = PasswordToKey (password, 7);
ct = des.CreateEncryptor ();
ct.TransformBlock (magic, 0, 8, buffer, 8);
}
des.Clear ();
return GetResponse (challenge, buffer);
}
static byte[] Compute_NTLM_Password (string password)
{
var buffer = new byte [21];
// create NT password
MD4 md4 = MD4.Create ();
byte[] data = ((password == null) ? (new byte [0]) : (Encoding.Unicode.GetBytes (password)));
byte[] hash = md4.ComputeHash (data);
Buffer.BlockCopy (hash, 0, buffer, 0, 16);
// clean up
Array.Clear (data, 0, data.Length);
Array.Clear (hash, 0, hash.Length);
return buffer;
}
static byte[] Compute_NTLM (string password, byte[] challenge)
{
var buffer = Compute_NTLM_Password (password);
return GetResponse (challenge, buffer);
}
static void Compute_NTLMv2_Session (string password, byte[] challenge,
out byte[] lm, out byte[] ntlm)
{
var nonce = new byte [8];
var rng = RandomNumberGenerator.Create ();
rng.GetBytes (nonce);
var sessionNonce = new byte [challenge.Length + 8];
challenge.CopyTo (sessionNonce, 0);
nonce.CopyTo (sessionNonce, challenge.Length);
lm = new byte [24];
nonce.CopyTo (lm, 0);
MD5 md5 = MD5.Create ();
var hash = md5.ComputeHash (sessionNonce);
var newChallenge = new byte [8];
Array.Copy (hash, newChallenge, 8);
ntlm = Compute_NTLM (password, newChallenge);
// clean up
Array.Clear (nonce, 0, nonce.Length);
Array.Clear (sessionNonce, 0, sessionNonce.Length);
Array.Clear (newChallenge, 0, newChallenge.Length);
Array.Clear (hash, 0, hash.Length);
}
static byte[] Compute_NTLMv2 (Type2Message type2, string username, string password, string domain)
{
var ntlm_hash = Compute_NTLM_Password (password);
var ubytes = Encoding.Unicode.GetBytes (username.ToUpperInvariant ());
var tbytes = Encoding.Unicode.GetBytes (domain);
var bytes = new byte [ubytes.Length + tbytes.Length];
ubytes.CopyTo (bytes, 0);
Array.Copy (tbytes, 0, bytes, ubytes.Length, tbytes.Length);
var md5 = new HMACMD5 (ntlm_hash);
var ntlm_v2_hash = md5.ComputeHash (bytes);
Array.Clear (ntlm_hash, 0, ntlm_hash.Length);
md5.Clear ();
var ntlm_v2_md5 = new HMACMD5 (ntlm_v2_hash);
var now = DateTime.Now;
var timestamp = now.Ticks - 504911232000000000;
var nonce = new byte [8];
var rng = RandomNumberGenerator.Create ();
rng.GetBytes (nonce);
byte[] blob = new byte [28 + type2.TargetInfo.Length];
blob[0] = 0x01;
blob[1] = 0x01;
Buffer.BlockCopy (BitConverterLE.GetBytes (timestamp), 0, blob, 8, 8);
Buffer.BlockCopy (nonce, 0, blob, 16, 8);
Buffer.BlockCopy (type2.TargetInfo, 0, blob, 28, type2.TargetInfo.Length);
var challenge = type2.Nonce;
var hashInput = new byte [challenge.Length + blob.Length];
challenge.CopyTo (hashInput, 0);
blob.CopyTo (hashInput, challenge.Length);
var blobHash = ntlm_v2_md5.ComputeHash (hashInput);
var response = new byte [blob.Length + blobHash.Length];
blobHash.CopyTo (response, 0);
blob.CopyTo (response, blobHash.Length);
Array.Clear (ntlm_v2_hash, 0, ntlm_v2_hash.Length);
ntlm_v2_md5.Clear ();
Array.Clear (nonce, 0, nonce.Length);
Array.Clear (blob, 0, blob.Length);
Array.Clear (hashInput, 0, hashInput.Length);
Array.Clear (blobHash, 0, blobHash.Length);
return response;
}
public static void Compute (Type2Message type2, NtlmAuthLevel level,
string username, string password, string domain,
out byte[] lm, out byte[] ntlm)
{
lm = null;
switch (level) {
case NtlmAuthLevel.LM_and_NTLM:
lm = Compute_LM (password, type2.Nonce);
ntlm = Compute_NTLM (password, type2.Nonce);
break;
case NtlmAuthLevel.LM_and_NTLM_and_try_NTLMv2_Session:
if ((type2.Flags & NtlmFlags.NegotiateNtlm2Key) == 0)
goto case NtlmAuthLevel.LM_and_NTLM;
Compute_NTLMv2_Session (password, type2.Nonce, out lm, out ntlm);
break;
case NtlmAuthLevel.NTLM_only:
if ((type2.Flags & NtlmFlags.NegotiateNtlm2Key) != 0)
Compute_NTLMv2_Session (password, type2.Nonce, out lm, out ntlm);
else
ntlm = Compute_NTLM (password, type2.Nonce);
break;
case NtlmAuthLevel.NTLMv2_only:
ntlm = Compute_NTLMv2 (type2, username, password, domain);
break;
default:
throw new InvalidOperationException ();
}
}
static byte[] GetResponse (byte[] challenge, 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;
}
static 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;
}
static byte[] PasswordToKey (string password, int position)
{
byte[] key7 = new byte [7];
int len = System.Math.Min (password.Length - position, 7);
Encoding.ASCII.GetBytes (password.ToUpper (CultureInfo.CurrentCulture), position, len, key7, 0);
byte[] key8 = PrepareDESKey (key7, 0);
// cleanup intermediate key material
Array.Clear (key7, 0, key7.Length);
return key8;
}
}
}

View File

@@ -0,0 +1,53 @@
2010-05-10 Sebastien Pouliot <sebastien@ximian.com>
* ChallengeResponse.cs: Let it compile for Moonlight (where the
file is compiled inside System.dll)
2004-11-05 Sebastien Pouliot <sebastien@ximian.com>
* MessageBase.cs: Fixed endian issue. Added globalization support.
* Type1Message.cs: Fixed endian issue. Added globalization support.
* Type2Message.cs: Fixed endian issue.
* Type3Message.cs: Fixed endian issue. Added globalization support.
2004-04-22 Sebastien Pouliot <sebastien@ximian.com>
* ChallengeResponse.cs: FxCop-ized.
* NtlmFlags.cs: FxCop-ized. CLS compliance.
* Type1Message.cs: FxCop-ized.
* Type3Message.cs: FxCop-ized.
2004-04-20 Sebastien Pouliot <sebastien@ximian.com>
* NtlmFlags.cs: Changed enum to int for CLS compliance.
2003-12-17 Sebastien Pouliot <spouliot@videotron.ca>
* ChallengeResponse.cs: Sorry I must have a profesionnal problem with
weak passwords ;-). Anyway I corrected the CR for null passwords (which
would produce a weak key for the first DES key) and added clean up :).
However it (null password) doesn't work for SQL Server authentication ?
2003-12-15 Sebastien Pouliot <spouliot@videotron.ca>
* ChallengeResponse.cs: Pre-calculated second part of the LM hash for
small password. Otherwise we get a DES weak key - which isn't
supported (exception) by the framework.
2003-12-02 Sebastien Pouliot <spouliot@videotron.ca>
* ChallengeResponse.cs: Fixed compilation error with mcs (System.Math.Min)
* Type2Message.cs: Fixed compilation warning for override. Flags are now
32 bits.
* Type3Message.cs: Fixed compilation warning for override. Removed (old)
header code to use base class. Changed 16 bits Options for 32 bits Flags
(NtlmFlags).
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.

View File

@@ -0,0 +1,109 @@
//
// Mono.Security.Protocol.Ntlm.MessageBase
// abstract class for all NTLM messages
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.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
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
namespace Mono.Security.Protocol.Ntlm {
#if INSIDE_SYSTEM
internal
#else
public
#endif
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) {
string msg = Locale.GetText ("Minimum message length is 12 bytes.");
throw new ArgumentOutOfRangeException ("message", message.Length, msg);
}
if (!CheckHeader (message)) {
string msg = String.Format (Locale.GetText ("Invalid Type{0} message."), _type);
throw new ArgumentException (msg, "message");
}
}
protected bool CheckHeader (byte[] message)
{
for (int i=0; i < header.Length; i++) {
if (message [i] != header [i])
return false;
}
return (BitConverterLE.ToUInt32 (message, 8) == _type);
}
public abstract byte[] GetBytes ();
}
}

View File

@@ -0,0 +1,60 @@
//
// NtlmAuthLevel.cs
//
// Author:
// Martin Baulig <martin.baulig@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace Mono.Security.Protocol.Ntlm {
/*
* On Windows, this is controlled by a registry setting
* (http://msdn.microsoft.com/en-us/library/ms814176.aspx)
*
* This can be configured by setting the static
* Type3Message.DefaultAuthLevel property, the default value
* is LM_and_NTLM_and_try_NTLMv2_Session.
*/
#if INSIDE_SYSTEM
internal
#else
public
#endif
enum NtlmAuthLevel {
/* Use LM and NTLM, never use NTLMv2 session security. */
LM_and_NTLM,
/* Use NTLMv2 session security if the server supports it,
* otherwise fall back to LM and NTLM. */
LM_and_NTLM_and_try_NTLMv2_Session,
/* Use NTLMv2 session security if the server supports it,
* otherwise fall back to NTLM. Never use LM. */
NTLM_only,
/* Use NTLMv2 only. */
NTLMv2_only,
}
}

View File

@@ -0,0 +1,70 @@
//
// Mono.Security.Protocol.Ntlm.NtlmFlags
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// (C) 2004 Novell (http://www.novell.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
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Security.Protocol.Ntlm {
[Flags]
#if INSIDE_SYSTEM
internal
#else
public
#endif
enum NtlmFlags : int {
// 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 = (unchecked ((int) 0x80000000))
}
}

View File

@@ -0,0 +1,85 @@
//
// NtlmSettings.cs
//
// Author:
// Martin Baulig <martin.baulig@xamarin.com>
//
// Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Net;
using System.Reflection;
namespace Mono.Security.Protocol.Ntlm {
/*
* On Windows, this is controlled by a registry setting
* (http://msdn.microsoft.com/en-us/library/ms814176.aspx)
*
* This can be configured by setting the static
* NtlmSettings.DefaultAuthLevel property, the default value
* is LM_and_NTLM_and_try_NTLMv2_Session.
*/
#if INSIDE_SYSTEM
internal
#else
public
#endif
static class NtlmSettings {
static NtlmAuthLevel defaultAuthLevel = NtlmAuthLevel.LM_and_NTLM_and_try_NTLMv2_Session;
static FieldInfo GetDefaultAuthLevelField ()
{
#if INSIDE_SYSTEM
return null;
#else
var type = typeof (HttpWebRequest).Assembly.GetType ("Mono.Security.Protocol.Ntlm.NtlmSettings", false);
if (type == null)
return null;
return type.GetField ("defaultAuthLevel", BindingFlags.Static | BindingFlags.NonPublic);
#endif
}
#if INSIDE_SYSTEM
internal
#else
public
#endif
static NtlmAuthLevel DefaultAuthLevel {
get {
var field = GetDefaultAuthLevelField ();
if (field != null)
return (NtlmAuthLevel)field.GetValue (null);
else
return defaultAuthLevel;
}
set {
var field = GetDefaultAuthLevelField ();
if (field != null)
field.SetValue (null, value);
else
defaultAuthLevel = value;
}
}
}
}

View File

@@ -0,0 +1,148 @@
//
// Mono.Security.Protocol.Ntlm.Type1Message - Negotiation
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.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
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.Text;
namespace Mono.Security.Protocol.Ntlm {
#if INSIDE_SYSTEM
internal
#else
public
#endif
class Type1Message : MessageBase {
private string _host;
private string _domain;
public Type1Message () : base (1)
{
// default values
_domain = Environment.UserDomainName;
_host = Environment.MachineName;
Flags = (NtlmFlags) 0xb207;
}
public Type1Message (byte[] message) : base (1)
{
Decode (message);
}
// properties
public string Domain {
get { return _domain; }
set {
if (value == null)
value = "";
if (value == "")
Flags &= ~NtlmFlags.NegotiateDomainSupplied;
else
Flags |= NtlmFlags.NegotiateDomainSupplied;
_domain = value;
}
}
public string Host {
get { return _host; }
set {
if (value == null)
value = "";
if (value == "")
Flags &= ~NtlmFlags.NegotiateWorkstationSupplied;
else
Flags |= NtlmFlags.NegotiateWorkstationSupplied;
_host = value;
}
}
// methods
protected override void Decode (byte[] message)
{
base.Decode (message);
Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 12);
int dom_len = BitConverterLE.ToUInt16 (message, 16);
int dom_off = BitConverterLE.ToUInt16 (message, 20);
_domain = Encoding.ASCII.GetString (message, dom_off, dom_len);
int host_len = BitConverterLE.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 (CultureInfo.InvariantCulture));
Buffer.BlockCopy (host, 0, data, 32, host.Length);
byte[] domain = Encoding.ASCII.GetBytes (_domain.ToUpper (CultureInfo.InvariantCulture));
Buffer.BlockCopy (domain, 0, data, dom_off, domain.Length);
return data;
}
}
}

View File

@@ -0,0 +1,146 @@
//
// Mono.Security.Protocol.Ntlm.Type2Message - Challenge
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.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
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Text;
using System.Security.Cryptography;
namespace Mono.Security.Protocol.Ntlm {
#if INSIDE_SYSTEM
internal
#else
public
#endif
class Type2Message : MessageBase {
private byte[] _nonce;
private string _targetName;
private byte[] _targetInfo;
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) {
string msg = Locale.GetText ("Invalid Nonce Length (should be 8 bytes).");
throw new ArgumentException (msg, "Nonce");
}
_nonce = (byte[]) value.Clone ();
}
}
public string TargetName {
get { return _targetName; }
}
public byte[] TargetInfo {
get { return (byte[])_targetInfo.Clone (); }
}
// methods
protected override void Decode (byte[] message)
{
base.Decode (message);
Flags = (NtlmFlags)BitConverterLE.ToUInt32 (message, 20);
Buffer.BlockCopy (message, 24, _nonce, 0, 8);
var tname_len = BitConverterLE.ToUInt16 (message, 12);
var tname_off = BitConverterLE.ToUInt16 (message, 16);
if (tname_len > 0) {
if ((Flags & NtlmFlags.NegotiateOem) != 0)
_targetName = Encoding.ASCII.GetString (message, tname_off, tname_len);
else
_targetName = Encoding.Unicode.GetString (message, tname_off, tname_len);
}
// The Target Info block is optional.
if (message.Length >= 48) {
var tinfo_len = BitConverterLE.ToUInt16 (message, 40);
var tinfo_off = BitConverterLE.ToUInt16 (message, 44);
if (tinfo_len > 0) {
_targetInfo = new byte [tinfo_len];
Buffer.BlockCopy (message, tinfo_off, _targetInfo, 0, tinfo_len);
}
}
}
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
data [20] = (byte) Flags;
data [21] = (byte)((uint)Flags >> 8);
data [22] = (byte)((uint)Flags >> 16);
data [23] = (byte)((uint)Flags >> 24);
Buffer.BlockCopy (_nonce, 0, data, 24, _nonce.Length);
return data;
}
}
}

View File

@@ -0,0 +1,361 @@
//
// Mono.Security.Protocol.Ntlm.Type3Message - Authentication
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.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
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.Text;
namespace Mono.Security.Protocol.Ntlm {
#if INSIDE_SYSTEM
internal
#else
public
#endif
class Type3Message : MessageBase {
private NtlmAuthLevel _level;
private byte[] _challenge;
private string _host;
private string _domain;
private string _username;
private string _password;
private Type2Message _type2;
private byte[] _lm;
private byte[] _nt;
internal const string LegacyAPIWarning =
"Use of this API is highly discouraged, " +
"it selects legacy-mode LM/NTLM authentication, which sends " +
"your password in very weak encryption over the wire even if " +
"the server supports the more secure NTLMv2 / NTLMv2 Session. " +
"You need to use the new `Type3Message (Type2Message)' constructor " +
"to use the more secure NTLMv2 / NTLMv2 Session authentication modes. " +
"These require the Type 2 message from the server to compute the response.";
[Obsolete (LegacyAPIWarning)]
public Type3Message () : base (3)
{
if (DefaultAuthLevel != NtlmAuthLevel.LM_and_NTLM)
throw new InvalidOperationException (
"Refusing to use legacy-mode LM/NTLM authentication " +
"unless explicitly enabled using DefaultAuthLevel.");
// default values
_domain = Environment.UserDomainName;
_host = Environment.MachineName;
_username = Environment.UserName;
_level = NtlmAuthLevel.LM_and_NTLM;
Flags = (NtlmFlags) 0x8201;
}
public Type3Message (byte[] message) : base (3)
{
Decode (message);
}
public Type3Message (Type2Message type2) : base (3)
{
_type2 = type2;
_level = DefaultAuthLevel;
_challenge = (byte[]) type2.Nonce.Clone ();
_domain = type2.TargetName;
_host = Environment.MachineName;
_username = Environment.UserName;
Flags = (NtlmFlags) 0x8200;
if ((type2.Flags & NtlmFlags.NegotiateUnicode) != 0)
Flags |= NtlmFlags.NegotiateUnicode;
else
Flags |= NtlmFlags.NegotiateOem;
if ((type2.Flags & NtlmFlags.NegotiateNtlm2Key) != 0)
Flags |= NtlmFlags.NegotiateNtlm2Key;
}
~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);
}
// Default auth level
[Obsolete ("Use NtlmSettings.DefaultAuthLevel")]
public static NtlmAuthLevel DefaultAuthLevel {
get { return NtlmSettings.DefaultAuthLevel; }
set { NtlmSettings.DefaultAuthLevel = value; }
}
public NtlmAuthLevel Level {
get { return _level; }
set { _level = value; }
}
// properties
[Obsolete (LegacyAPIWarning)]
public byte[] Challenge {
get {
if (_challenge == null)
return null;
return (byte[]) _challenge.Clone (); }
set {
if ((_type2 != null) || (_level != NtlmAuthLevel.LM_and_NTLM))
throw new InvalidOperationException (
"Refusing to use legacy-mode LM/NTLM authentication " +
"unless explicitly enabled using DefaultAuthLevel.");
if (value == null)
throw new ArgumentNullException ("Challenge");
if (value.Length != 8) {
string msg = Locale.GetText ("Invalid Challenge Length (should be 8 bytes).");
throw new ArgumentException (msg, "Challenge");
}
_challenge = (byte[]) value.Clone ();
}
}
public string Domain {
get { return _domain; }
set {
if (value == null)
value = "";
if (value == "")
Flags &= ~NtlmFlags.NegotiateDomainSupplied;
else
Flags |= NtlmFlags.NegotiateDomainSupplied;
_domain = value;
}
}
public string Host {
get { return _host; }
set {
if (value == null)
value = "";
if (value == "")
Flags &= ~NtlmFlags.NegotiateWorkstationSupplied;
else
Flags |= NtlmFlags.NegotiateWorkstationSupplied;
_host = 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; }
set { _nt = value; }
}
// methods
protected override void Decode (byte[] message)
{
base.Decode (message);
_password = null;
if (message.Length >= 64)
Flags = (NtlmFlags)BitConverterLE.ToUInt32 (message, 60);
else
Flags = (NtlmFlags)0x8201;
int lm_len = BitConverterLE.ToUInt16 (message, 12);
int lm_off = BitConverterLE.ToUInt16 (message, 16);
_lm = new byte [lm_len];
Buffer.BlockCopy (message, lm_off, _lm, 0, lm_len);
int nt_len = BitConverterLE.ToUInt16 (message, 20);
int nt_off = BitConverterLE.ToUInt16 (message, 24);
_nt = new byte [nt_len];
Buffer.BlockCopy (message, nt_off, _nt, 0, nt_len);
int dom_len = BitConverterLE.ToUInt16 (message, 28);
int dom_off = BitConverterLE.ToUInt16 (message, 32);
_domain = DecodeString (message, dom_off, dom_len);
int user_len = BitConverterLE.ToUInt16 (message, 36);
int user_off = BitConverterLE.ToUInt16 (message, 40);
_username = DecodeString (message, user_off, user_len);
int host_len = BitConverterLE.ToUInt16 (message, 44);
int host_off = BitConverterLE.ToUInt16 (message, 48);
_host = DecodeString (message, host_off, host_len);
// Session key. We don't use it yet.
// int skey_len = BitConverterLE.ToUInt16 (message, 52);
// int skey_off = BitConverterLE.ToUInt16 (message, 56);
}
string DecodeString (byte[] buffer, int offset, int len)
{
if ((Flags & NtlmFlags.NegotiateUnicode) != 0)
return Encoding.Unicode.GetString (buffer, offset, len);
else
return Encoding.ASCII.GetString (buffer, offset, len);
}
byte[] EncodeString (string text)
{
if (text == null)
return new byte [0];
if ((Flags & NtlmFlags.NegotiateUnicode) != 0)
return Encoding.Unicode.GetBytes (text);
else
return Encoding.ASCII.GetBytes (text);
}
public override byte[] GetBytes ()
{
byte[] target = EncodeString (_domain);
byte[] user = EncodeString (_username);
byte[] host = EncodeString (_host);
byte[] lm, ntlm;
if (_type2 == null) {
if (_level != NtlmAuthLevel.LM_and_NTLM)
throw new InvalidOperationException (
"Refusing to use legacy-mode LM/NTLM authentication " +
"unless explicitly enabled using DefaultAuthLevel.");
using (var legacy = new ChallengeResponse (_password, _challenge)) {
lm = legacy.LM;
ntlm = legacy.NT;
}
} else {
ChallengeResponse2.Compute (_type2, _level, _username, _password, _domain, out lm, out ntlm);
}
var lmresp_len = lm != null ? lm.Length : 0;
var ntresp_len = ntlm != null ? ntlm.Length : 0;
byte[] data = PrepareMessage (64 + target.Length + user.Length + host.Length + lmresp_len + ntresp_len);
// LM response
short lmresp_off = (short)(64 + target.Length + user.Length + host.Length);
data [12] = (byte)lmresp_len;
data [13] = (byte)0x00;
data [14] = (byte)lmresp_len;
data [15] = (byte)0x00;
data [16] = (byte)lmresp_off;
data [17] = (byte)(lmresp_off >> 8);
// NT response
short ntresp_off = (short)(lmresp_off + lmresp_len);
data [20] = (byte)ntresp_len;
data [21] = (byte)(ntresp_len >> 8);
data [22] = (byte)ntresp_len;
data [23] = (byte)(ntresp_len >> 8);
data [24] = (byte)ntresp_off;
data [25] = (byte)(ntresp_off >> 8);
// target
short dom_len = (short)target.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);
int flags = (int)Flags;
// options flags
data [60] = (byte)flags;
data [61] = (byte)((uint)flags >> 8);
data [62] = (byte)((uint)flags >> 16);
data [63] = (byte)((uint)flags >> 24);
Buffer.BlockCopy (target, 0, data, dom_off, target.Length);
Buffer.BlockCopy (user, 0, data, uname_off, user.Length);
Buffer.BlockCopy (host, 0, data, host_off, host.Length);
if (lm != null) {
Buffer.BlockCopy (lm, 0, data, lmresp_off, lm.Length);
Array.Clear (lm, 0, lm.Length);
}
Buffer.BlockCopy (ntlm, 0, data, ntresp_off, ntlm.Length);
Array.Clear (ntlm, 0, ntlm.Length);
return data;
}
}
}