869 lines
30 KiB
Plaintext
869 lines
30 KiB
Plaintext
{
|
|
$Project$
|
|
$Workfile$
|
|
$Revision$
|
|
$DateUTC$
|
|
$Id$
|
|
|
|
This file is part of the Indy (Internet Direct) project, and is offered
|
|
under the dual-licensing agreement described on the Indy website.
|
|
(http://www.indyproject.org/)
|
|
|
|
Copyright:
|
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
|
}
|
|
{
|
|
$Log$
|
|
}
|
|
{
|
|
Rev 1.1 6/29/04 12:51:10 PM RLebeau
|
|
Updatd SetupLanManagerPassword() to check the password length before
|
|
referencing the password data
|
|
|
|
Rev 1.0 11/13/2002 07:58:08 AM JPMugaas
|
|
|
|
S.G. 12/7/2002:
|
|
- Rewrote Type 1 and Type 2 structures to be closer to the
|
|
document referenced in the above URL. (Easier to read and check)
|
|
- Corrected falgs accouring to bug ID 577895 and own packet traces.
|
|
This was actually only an adjustment to the new data types when
|
|
I rewrote the header.
|
|
- Initialized structures to #0 before using.
|
|
}
|
|
{
|
|
Implementation of the NTLM authentication as specified in
|
|
http://www.innovation.ch/java/ntlm.html with some fixes
|
|
|
|
Author: Doychin Bondzhev (doychin@dsoft-bg.com)
|
|
Copyright: (c) Chad Z. Hower and The Winshoes Working Group.
|
|
}
|
|
|
|
unit IdNTLM;
|
|
|
|
interface
|
|
|
|
{$i IdCompilerDefines.inc}
|
|
|
|
uses
|
|
IdGlobal,
|
|
IdStruct;
|
|
|
|
type
|
|
{$IFDEF DOTNET}
|
|
ProtocolArray = array [1..8] of AnsiChar;
|
|
padArray2 = array[0..1] of Byte;
|
|
padArray3 = Array[0..2] of Byte;
|
|
padArray7 = Array[0..6] of Byte;
|
|
padArray8 = Array[0..7] of Byte;
|
|
nonceArray = Array[1..8] of Byte;
|
|
|
|
ntlm_base = class(TIdStruct)
|
|
protected
|
|
fprotocol : ProtocolArray;
|
|
function GetBytesLen: UInt32; override;
|
|
public
|
|
procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override;
|
|
procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override;
|
|
|
|
property protocol: ProtocolArray read fprotocol write fprotocol; // array [1..8] of Char; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize}
|
|
end;
|
|
|
|
type_1_message_header = class(ntlm_base)
|
|
protected
|
|
f_type : UInt8;
|
|
fpad : padArray3;
|
|
fflags : UInt16;
|
|
fpad2 : padArray2;
|
|
fdom_len1 : UInt16;
|
|
fdom_len2 : UInt16;
|
|
fdom_off : UInt32;
|
|
fhost_len1 : UInt16;
|
|
fhost_len2 : UInt16;
|
|
fhost_off : UInt32;
|
|
function GetBytesLen: UInt32; override;
|
|
|
|
public
|
|
procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override;
|
|
procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override;
|
|
|
|
property _type: UInt8 read f_type write f_type; // 0x01
|
|
property pad : padArray3 read fpad write fpad; // 0x0
|
|
property flags: UInt16 read fflags write fflags; // 0xb203
|
|
property pad2 : padArray2 read fpad2 write fpad2; // 0x0
|
|
property dom_len1: UInt16 read fdom_len1 write fdom_len1; // domain string length
|
|
property dom_len2: UInt16 read fdom_len2 write fdom_len2; // domain string length
|
|
property dom_off: UInt32 read fdom_off write fdom_off; // domain string offset
|
|
|
|
property host_len1: UInt16 read fhost_len1 write fhost_len1; // host string length
|
|
property host_len2: UInt16 read fhost_len2 write fhost_len2; // host string length
|
|
property host_off: UInt32 read fhost_off write fhost_off; // host string offset (always 0x20)
|
|
end;
|
|
|
|
type_2_message_header = class(ntlm_base)
|
|
protected
|
|
f_type : UInt8;
|
|
fPad: padArray3;
|
|
fhost_len1: UInt16;
|
|
fhost_len2: UInt16;
|
|
fhost_off: UInt32;
|
|
fflags: UInt16;
|
|
fPad2: padArray2;
|
|
fnonce: nonceArray;
|
|
freserved: padArray8;
|
|
finfo_len1: UInt16;
|
|
finfo_len2: UInt16;
|
|
finfo_off: UInt32;
|
|
|
|
function GetBytesLen: UInt32; override;
|
|
public
|
|
procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override;
|
|
procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override;
|
|
|
|
property _type: UInt8 read f_type write f_type; // $2
|
|
property pad: padArray3 read fPad wrie fPad;
|
|
property host_len1: UInt16 read fhost_len1 write fhost_len1;
|
|
property host_len2: UInt16 read fhost_len2 write fhost_len2;
|
|
property host_off: UInt32 read fhost_off write fhost_off;
|
|
property flags: UInt16 read fflags write fflags;
|
|
property pad2: padArray2 read fflags write fflags;
|
|
property nonce: nonceArray read fnonce write fnonce;
|
|
property reserved: padArray8 read freserved write freserved;
|
|
property info_len1: UInt16 read finfo_len1 write finfo_len1;
|
|
property info_len2: UInt16 read finfo_len2 write finfo_len2;
|
|
property info_off: UInt32 read finfo_off write finfo_off;
|
|
end;
|
|
|
|
type_3_message_header = class(ntlm_base)
|
|
protected
|
|
f_type: UInt32;
|
|
flm_resp_len1: UInt16;
|
|
flm_resp_len2: UInt16;
|
|
flm_resp_off : UInt32;
|
|
fnt_resp_len1: UInt16;
|
|
fnt_resp_len2: UInt16;
|
|
fnt_resp_off: UInt32;
|
|
fdom_len1: UInt16;
|
|
fdom_len2 : UInt16;
|
|
fdom_off : UInt32;
|
|
fuser_len1: UInt16;
|
|
fuser_len2: UInt16;
|
|
fuser_off: UInt32;
|
|
fhost_len1: UInt16;
|
|
fhost_len2: UInt16;
|
|
fhost_off: UInt32;
|
|
fkey_len1: UInt16;
|
|
fkey_len2: UInt16;
|
|
fkey_off: UInt32;
|
|
fflags: UInt32;
|
|
function GetBytesLen: UInt32; override;
|
|
public
|
|
procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override;
|
|
procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override;
|
|
|
|
property _type: UInt32 read f_type write f_type; // 0x03
|
|
|
|
property lm_resp_len1: UInt16 read flm_resp_len1 write flm_resp_len1; // LanManager response length (always 0x18)
|
|
property lm_resp_len2: UInt16 read flm_resp_len2 write flm_resp_len2; // LanManager response length (always 0x18)
|
|
property lm_resp_off: UInt32 read flm_resp_off write flm_resp_off; // LanManager response offset
|
|
|
|
property nt_resp_len1: UInt16 read fnt_resp_len1 write fnt_resp_len1; // NT response length (always 0x18)
|
|
property nt_resp_len2: UInt16 read fnt_resp_len2 write fnt_resp_len2; // NT response length (always 0x18)
|
|
property nt_resp_off: UInt32 read fnt_resp_off write fnt_resp_off; // NT response offset
|
|
|
|
property dom_len1: UInt16 read fdom_len1 write fdom_len1; // domain string length
|
|
property dom_len2: UInt16 read fdom_len2 write fdom_len2; // domain string length
|
|
property dom_off: UInt32 read fdom_off write fdom_off; // domain string offset (always 0x40)
|
|
|
|
property user_len1: UInt16 read fuser_len1 write fuser_len1; // username string length
|
|
property user_len2: UInt16 read fuser_len2 write fuser_len2; // username string length
|
|
property user_off: UInt32 read fuser_off write fuser_off; // username string offset
|
|
|
|
property host_len1: UInt16 read fhost_len1 write fhost_len1; // host string length
|
|
property host_len2: UInt16 read fhost_len2 write fhost_len2; // host string length
|
|
property host_off: UInt32 read fhost_off write fhost_off; // host string offset
|
|
|
|
property key_len1: UInt16 read fkey_len1 write fkey_len1; // session key length
|
|
property key_len2: UInt16 read fkey_len2 write fkey_len2; // session key length
|
|
property key_off: UInt32 read fkey_off write fkey_off; // session key offset
|
|
|
|
property flags: UInt32 read fflags write fflags; // 0xA0808205
|
|
end;
|
|
{$ELSE}
|
|
type_1_message_header = packed record
|
|
protocol: array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize}
|
|
_type: UInt8; // 0x01
|
|
pad : packed Array[1..3] of UInt8; // 0x0
|
|
flags: UInt16; // 0xb203
|
|
pad2 : packed Array[1..2] of UInt8; // 0x0
|
|
dom_len1: UInt16; // domain string length
|
|
dom_len2: UInt16; // domain string length
|
|
dom_off: UInt32; // domain string offset
|
|
|
|
host_len1: UInt16; // host string length
|
|
host_len2: UInt16; // host string length
|
|
host_off: UInt32; // host string offset (always 0x20)
|
|
end;
|
|
|
|
type_2_message_header = packed record
|
|
protocol: packed array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', #0 {Do not Localize}
|
|
_type: UInt8; // $2
|
|
Pad: packed Array[1..3] of UInt8;
|
|
host_len1: UInt16;
|
|
host_len2: UInt16;
|
|
host_off: UInt32;
|
|
flags: UInt16;
|
|
Pad2: packed Array[1..2] of UInt8;
|
|
nonce: packed Array[1..8] of UInt8;
|
|
reserved: packed Array[1..8] of UInt8;
|
|
info_len1: UInt16;
|
|
info_len2: UInt16;
|
|
info_off: UInt32;
|
|
end;
|
|
|
|
type_3_message_header = packed record
|
|
protocol: array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize}
|
|
_type: UInt32; // 0x03
|
|
|
|
lm_resp_len1: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_len2: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_off: UInt32; // LanManager response offset
|
|
|
|
nt_resp_len1: UInt16; // NT response length (always 0x18)
|
|
nt_resp_len2: UInt16; // NT response length (always 0x18)
|
|
nt_resp_off: UInt32; // NT response offset
|
|
|
|
dom_len1: UInt16; // domain string length
|
|
dom_len2: UInt16; // domain string length
|
|
dom_off: UInt32; // domain string offset (always 0x40)
|
|
|
|
user_len1: UInt16; // username string length
|
|
user_len2: UInt16; // username string length
|
|
user_off: UInt32; // username string offset
|
|
|
|
host_len1: UInt16; // host string length
|
|
host_len2: UInt16; // host string length
|
|
host_off: UInt32; // host string offset
|
|
|
|
key_len1: UInt16; // session key length
|
|
key_len2: UInt16; // session key length
|
|
key_off: UInt32; // session key offset
|
|
|
|
flags: UInt32; // 0xA0808205
|
|
end;
|
|
|
|
function BuildType1Message(const ADomain, AHost: String): String;
|
|
function BuildType3Message(const ADomain, AHost, AUsername: TIdUnicodeString; const APassword: String; const ANonce: TIdBytes): String;
|
|
{$ENDIF}
|
|
|
|
function NTLMFunctionsLoaded : Boolean;
|
|
|
|
procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
|
|
|
|
//IMPORTANT!!!
|
|
//
|
|
//NTLM is a funny protocol because it was designed for little endian machines.
|
|
//Some record values must be in little endian byte-orders.
|
|
|
|
const
|
|
// S.G. 12/7/2002: Changed the flag to $B207 (from BugID 577895 and packet trace)
|
|
//was $A000B207; //b203;
|
|
//JPM - note that this value has to be little endian. We precalculate
|
|
//this for big endian machines.
|
|
MSG1_FLAGS : UInt16 = $b207;
|
|
// S.G. 12/7/2002: was: flags := $A0808205; (from BugID 577895 and packet trace)
|
|
MSG3_FLAGS : UInt32 = $018205;
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF HAS_UNIT_AnsiStrings}
|
|
AnsiStrings,
|
|
{$ENDIF}
|
|
SysUtils,
|
|
{$IFDEF DOTNET}
|
|
System.Text,
|
|
{$ENDIF}
|
|
IdFIPS,
|
|
IdGlobalProtocols,
|
|
IdHash,
|
|
IdHashMessageDigest,
|
|
IdCoderMIME
|
|
{$IFNDEF DOTNET}, IdSSLOpenSSLHeaders{$ENDIF}
|
|
{$IFDEF HAS_GENERICS_TArray_Copy}
|
|
{$IFDEF HAS_UNIT_Generics_Collections}
|
|
, System.Generics.Collections
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
;
|
|
|
|
type
|
|
Pdes_key_schedule = ^des_key_schedule;
|
|
|
|
const
|
|
cProtocolStr: array[1..8] of Byte = (Ord('N'),Ord('T'),Ord('L'),Ord('M'),Ord('S'),Ord('S'),Ord('P'),$0); {Do not Localize}
|
|
|
|
procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
|
|
{$IFDEF USE_INLINE} inline; {$ENDIF}
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := Pos('\', AUsername);
|
|
if i > -1 then
|
|
begin
|
|
VDomain := Copy(AUsername, 1, i - 1);
|
|
VUserName := Copy(AUsername, i + 1, Length(AUserName));
|
|
end else
|
|
begin
|
|
VDomain := ' '; {do not localize}
|
|
VUserName := AUserName;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF DOTNET}
|
|
function NTLMFunctionsLoaded : Boolean;
|
|
{$IFDEF USE_INLINE} inline; {$ENDIF}
|
|
begin
|
|
Result := True;
|
|
end;
|
|
{$ELSE}
|
|
function NTLMFunctionsLoaded : Boolean;
|
|
begin
|
|
Result := IdSSLOpenSSLHeaders.Load;
|
|
if Result then begin
|
|
Result := Assigned(DES_set_odd_parity) and
|
|
Assigned(DES_set_key) and
|
|
Assigned(DES_ecb_encrypt);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF DOTNET}
|
|
{/*
|
|
* turns a 56 bit key into the 64 bit, odd parity key and sets the key.
|
|
* The key schedule ks is also set.
|
|
*/}
|
|
procedure setup_des_key(key_56: des_cblock; Var ks: des_key_schedule);
|
|
Var
|
|
key: des_cblock;
|
|
begin
|
|
key[0] := key_56[0];
|
|
|
|
key[1] := ((key_56[0] SHL 7) and $FF) or (key_56[1] SHR 1);
|
|
key[2] := ((key_56[1] SHL 6) and $FF) or (key_56[2] SHR 2);
|
|
key[3] := ((key_56[2] SHL 5) and $FF) or (key_56[3] SHR 3);
|
|
key[4] := ((key_56[3] SHL 4) and $FF) or (key_56[4] SHR 4);
|
|
key[5] := ((key_56[4] SHL 3) and $FF) or (key_56[5] SHR 5);
|
|
key[6] := ((key_56[5] SHL 2) and $FF) or (key_56[6] SHR 6);
|
|
key[7] := (key_56[6] SHL 1) and $FF;
|
|
|
|
DES_set_odd_parity(@key);
|
|
DES_set_key(@key, ks);
|
|
end;
|
|
|
|
{/*
|
|
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
|
|
* 8 byte plaintext is encrypted with each key and the resulting 24
|
|
* bytes are stored in the results array.
|
|
*/}
|
|
procedure calc_resp(keys: PDES_cblock; const ANonce: TIdBytes; results: Pdes_key_schedule);
|
|
Var
|
|
ks: des_key_schedule;
|
|
nonce: des_cblock;
|
|
begin
|
|
setup_des_key(keys^, ks);
|
|
Move(ANonce[0], nonce, 8);
|
|
des_ecb_encrypt(@nonce, Pconst_DES_cblock(results), ks, DES_ENCRYPT);
|
|
|
|
setup_des_key(PDES_cblock(PtrUInt(keys) + 7)^, ks);
|
|
des_ecb_encrypt(@nonce, Pconst_DES_cblock(PtrUInt(results) + 8), ks, DES_ENCRYPT);
|
|
|
|
setup_des_key(PDES_cblock(PtrUInt(keys) + 14)^, ks);
|
|
des_ecb_encrypt(@nonce, Pconst_DES_cblock(PtrUInt(results) + 16), ks, DES_ENCRYPT);
|
|
end;
|
|
|
|
Const
|
|
Magic: des_cblock = ($4B, $47, $53, $21, $40, $23, $24, $25 );
|
|
|
|
//* setup LanManager password */
|
|
function SetupLanManagerPassword(const APassword: String; const ANonce: TIdBytes): TIdBytes;
|
|
var
|
|
lm_hpw: array[0..20] of Byte;
|
|
lm_pw: array[0..13] of Byte;
|
|
idx, len: Integer;
|
|
ks: des_key_schedule;
|
|
lm_resp: array [0..23] of Byte;
|
|
lPassword: {$IFDEF STRING_IS_UNICODE}TIdBytes{$ELSE}AnsiString{$ENDIF};
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
lPassword := IndyTextEncoding_OSDefault.GetBytes(UpperCase(APassword));
|
|
{$ELSE}
|
|
lPassword := UpperCase(APassword);
|
|
{$ENDIF}
|
|
|
|
len := IndyMin(Length(lPassword), 14);
|
|
if len > 0 then begin
|
|
Move(lPassword[{$IFDEF STRING_IS_UNICODE}0{$ELSE}1{$ENDIF}], lm_pw[0], len);
|
|
end;
|
|
if len < 14 then begin
|
|
for idx := len to 13 do begin
|
|
lm_pw[idx] := $0;
|
|
end;
|
|
end;
|
|
|
|
//* create LanManager hashed password */
|
|
|
|
setup_des_key(pdes_cblock(@lm_pw[0])^, ks);
|
|
des_ecb_encrypt(@magic, Pconst_DES_cblock(@lm_hpw[0]), ks, DES_ENCRYPT);
|
|
|
|
setup_des_key(pdes_cblock(PtrUInt(@lm_pw[0]) + 7)^, ks);
|
|
des_ecb_encrypt(@magic, Pconst_DES_cblock(PtrUInt(@lm_hpw[0]) + 8), ks, DES_ENCRYPT);
|
|
|
|
FillChar(lm_hpw[16], 5, 0);
|
|
|
|
calc_resp(PDes_cblock(@lm_hpw[0]), ANonce, Pdes_key_schedule(@lm_resp[0]));
|
|
|
|
SetLength(Result, SizeOf(lm_resp));
|
|
Move(lm_resp[0], Result[0], SizeOf(lm_resp));
|
|
end;
|
|
|
|
function BuildUnicode(const S: String): TIdBytes;
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
{$ELSE}
|
|
var
|
|
i: integer;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
Result := IndyTextEncoding_UTF16LE.GetBytes(S);
|
|
{$ELSE}
|
|
// RLebeau: TODO - should this use encUTF16LE as well? This logic will
|
|
// not produce a valid Unicode string if non-ASCII characters are present!
|
|
SetLength(Result, Length(S) * SizeOf(WideChar));
|
|
for i := 0 to Length(S)-1 do begin
|
|
Result[i*2] := Byte(S[i+1]);
|
|
Result[(i*2)+1] := Byte(#0);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
//* create NT hashed password */
|
|
function CreateNTPassword(const APassword: String; const ANonce: TIdBytes): TIdBytes;
|
|
var
|
|
nt_hpw: array [1..21] of Byte;
|
|
nt_hpw128: TIdBytes;
|
|
nt_resp: array [1..24] of Byte;
|
|
LMD4: TIdHashMessageDigest4;
|
|
begin
|
|
CheckMD4Permitted;
|
|
LMD4 := TIdHashMessageDigest4.Create;
|
|
try
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
nt_hpw128 := LMD4.HashString(APassword, IndyTextEncoding_UTF16LE);
|
|
{$ELSE}
|
|
nt_hpw128 := LMD4.HashBytes(BuildUnicode(APassword));
|
|
{$ENDIF}
|
|
finally
|
|
LMD4.Free;
|
|
end;
|
|
|
|
Move(nt_hpw128[0], nt_hpw[1], 16);
|
|
FillChar(nt_hpw[17], 5, 0);
|
|
|
|
calc_resp(pdes_cblock(@nt_hpw[1]), ANonce, Pdes_key_schedule(@nt_resp[1]));
|
|
|
|
SetLength(Result, SizeOf(nt_resp));
|
|
Move(nt_resp[1], Result[0], SizeOf(nt_resp));
|
|
end;
|
|
|
|
function BuildType1Message(const ADomain, AHost: String): String;
|
|
var
|
|
LEncoding: IIdTextEncoding;
|
|
Type_1_Message: type_1_message_header;
|
|
lDomain: TIdBytes;
|
|
lHost: TIdBytes;
|
|
buf: TIdBytes;
|
|
begin
|
|
LEncoding := IndyTextEncoding_ASCII;
|
|
lDomain := ToBytes(UpperCase(ADomain), LEncoding);
|
|
lHost := ToBytes(UpperCase(AHost), LEncoding);
|
|
LEncoding := nil;
|
|
|
|
FillChar(Type_1_Message, SizeOf(Type_1_Message), #0);
|
|
|
|
{$IFDEF HAS_GENERICS_TArray_Copy}
|
|
TArray.Copy<Byte>(cProtocolStr, Type_1_Message.protocol, 8);
|
|
{$ELSE}
|
|
{$IFDEF USE_MARSHALLED_PTRS}
|
|
buf := cProtocolStr;
|
|
TMarshal.Copy(TBytesPtr(@buf)^, 0, TPtrWrapper.Create(@Type_1_Message.protocol[1]), 8);
|
|
{$ELSE}
|
|
Move(cProtocolStr[1], Type_1_Message.protocol[1], 8);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
Type_1_Message._type := 1;
|
|
|
|
// S.G. 12/7/2002: Changed the flag to $B207 (from BugID 577895 and packet trace)
|
|
Type_1_Message.flags := MSG1_FLAGS; //was $A000B207; //b203;
|
|
|
|
Type_1_Message.dom_len1 := UInt16(Length(lDomain));
|
|
// dom_off := 0;
|
|
Type_1_Message.dom_off := 32;
|
|
|
|
Type_1_Message.host_len1 := UInt16(Length(lHost));
|
|
Type_1_Message.host_off := UInt32(Type_1_Message.dom_off + Type_1_Message.dom_len1);
|
|
|
|
Type_1_Message._type := HostToLittleEndian(Type_1_Message._type);
|
|
Type_1_Message.flags := HostToLittleEndian(Type_1_Message.flags);
|
|
Type_1_Message.dom_len1 := HostToLittleEndian(Type_1_Message.dom_len1);
|
|
Type_1_Message.dom_len2 := Type_1_Message.dom_len1;
|
|
Type_1_Message.dom_off := HostToLittleEndian(Type_1_Message.dom_off);
|
|
Type_1_Message.host_len1 := HostToLittleEndian(Type_1_Message.host_len1);
|
|
Type_1_Message.host_len2 := Type_1_Message.host_len1;
|
|
Type_1_Message.host_off := HostToLittleEndian(Type_1_Message.host_off);
|
|
|
|
buf := RawToBytes(Type_1_Message, SizeOf(Type_1_Message));
|
|
AppendBytes(buf, lDomain);
|
|
AppendBytes(buf, lHost);
|
|
|
|
Result := TIdEncoderMIME.EncodeBytes(buf);
|
|
end;
|
|
|
|
function BuildType3Message(const ADomain, AHost, AUsername: TIdUnicodeString;
|
|
const APassword: String; const ANonce: TIdBytes): String;
|
|
var
|
|
type3: type_3_message_header;
|
|
buf: TIdBytes;
|
|
lm_password: TIdBytes;
|
|
nt_password: TIdBytes;
|
|
lDomain: TIdBytes;
|
|
lHost: TIdBytes;
|
|
lUsername: TIdBytes;
|
|
begin
|
|
lm_password := SetupLanManagerPassword(APassword, ANonce);
|
|
nt_password := CreateNTPassword(APassword, ANonce);
|
|
|
|
lDomain := BuildUnicode(UpperCase(ADomain));
|
|
lHost := BuildUnicode(UpperCase(AHost));
|
|
lUsername := BuildUnicode(AUsername);
|
|
|
|
{$IFDEF HAS_GENERICS_TArray_Copy}
|
|
TArray.Copy<Byte>(cProtocolStr, Type3.protocol, 8);
|
|
{$ELSE}
|
|
{$IFDEF USE_MARSHALLED_PTRS}
|
|
buf := cProtocolStr;
|
|
TMarshal.Copy(TBytesPtr(@buf)^, 0, TPtrWrapper.Create(@Type3.protocol[1]), 8);
|
|
{$ELSE}
|
|
Move(cProtocolStr[1], Type3.protocol[1], 8);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
Type3._type := 3;
|
|
|
|
Type3.lm_resp_len1 := UInt16(Length(lm_password));
|
|
Type3.lm_resp_off := $40;
|
|
|
|
Type3.nt_resp_len1 := UInt16(Length(nt_password));
|
|
Type3.nt_resp_off := UInt32(Type3.lm_resp_off + Type3.lm_resp_len1);
|
|
|
|
Type3.dom_len1 := UInt16(Length(lDomain));
|
|
Type3.dom_off := UInt32(Type3.nt_resp_off + Type3.nt_resp_len1);
|
|
|
|
Type3.user_len1 := UInt16(Length(lUsername));
|
|
Type3.user_off := UInt32(Type3.dom_off + Type3.dom_len1);
|
|
|
|
Type3.host_len1 := UInt16(Length(lHost));
|
|
Type3.host_off := UInt32(Type3.user_off + Type3.user_len1);
|
|
|
|
Type3.key_len1 := 0;
|
|
Type3.key_off := UInt32(Type3.user_len1 + Type3.host_len1);
|
|
|
|
Type3.flags := MSG3_FLAGS;
|
|
|
|
Type3._type := HostToLittleEndian(Type3._type);
|
|
Type3.lm_resp_len1 := HostToLittleEndian(Type3.lm_resp_len1);
|
|
Type3.lm_resp_len2 := Type3.lm_resp_len1;
|
|
Type3.lm_resp_off := HostToLittleEndian(Type3.lm_resp_off);
|
|
Type3.nt_resp_len1 := HostToLittleEndian(Type3.nt_resp_len1);
|
|
Type3.nt_resp_len2 := Type3.nt_resp_len1;
|
|
Type3.nt_resp_off := HostToLittleEndian(Type3.nt_resp_off);
|
|
Type3.dom_len1 := HostToLittleEndian(Type3.dom_len1);
|
|
Type3.dom_len2 := Type3.dom_len1;
|
|
Type3.dom_off := HostToLittleEndian(Type3.dom_off);
|
|
Type3.user_len1 := HostToLittleEndian(Type3.user_len1);
|
|
Type3.user_len2 := Type3.user_len1;
|
|
Type3.user_off := HostToLittleEndian(Type3.user_off);
|
|
Type3.host_len1 := HostToLittleEndian(Type3.host_len1);
|
|
Type3.host_len2 := Type3.host_len1;
|
|
Type3.host_off := HostToLittleEndian(Type3.host_off);
|
|
Type3.key_len1 := HostToLittleEndian(Type3.key_len1);
|
|
Type3.key_len2 := Type3.key_len1;
|
|
Type3.key_off := HostToLittleEndian(Type3.key_off);
|
|
Type3.flags := HostToLittleEndian(Type3.flags);
|
|
|
|
buf := RawToBytes(Type3, SizeOf(Type3));
|
|
AppendBytes(buf, lm_password);
|
|
AppendBytes(buf, nt_password);
|
|
AppendBytes(buf, lDomain);
|
|
AppendBytes(buf, lUsername);
|
|
AppendBytes(buf, lHost);
|
|
|
|
Result := TIdEncoderMIME.EncodeBytes(buf);
|
|
end;
|
|
|
|
{$ELSE}
|
|
|
|
procedure BytesToCharArray(const ABytes : TIdBytes; var VArray : Array of Char; const AIndex : Integer = 0);
|
|
var
|
|
i, ll, lh : Integer;
|
|
begin
|
|
ll := Low(VArray);
|
|
lh := High(Varray);
|
|
for i := ll to lh do begin
|
|
VArray[i] := Char(ABytes[ (i - ll)+ AIndex]);
|
|
end;
|
|
end;
|
|
|
|
procedure BytesToByteArray(const ABytes : TIdBytes; var VArray : Array of Byte; const AIndex : Integer = 0);
|
|
var
|
|
i, ll, lh : Integer;
|
|
begin
|
|
ll := Low(VArray);
|
|
lh := High(Varray);
|
|
for i := ll to lh do begin
|
|
VArray[i] := ABytes[ (i - ll)+ AIndex];
|
|
end;
|
|
end;
|
|
|
|
procedure ByteArrayToBytes(const VArray : array of Byte; const ABytes : TIdBytes; const AIndex : Integer = 0);
|
|
var
|
|
i, ll, lh : Integer;
|
|
begin
|
|
ll := Low(VArray);
|
|
lh := High(Varray);
|
|
for i := ll to lh do begin
|
|
ABytes[ (i - ll)+ AIndex] := VArray[i];
|
|
end;
|
|
end;
|
|
|
|
function ntlm_base.GetBytesLen: UInt32;
|
|
begin
|
|
Result := 8;
|
|
end;
|
|
|
|
procedure ntlm_base.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32);
|
|
var
|
|
i : Integer;
|
|
begin
|
|
inherited ReadStruct(ABytes,VIndex);
|
|
for i := 1 to Length(fprotocol) do
|
|
begin
|
|
fprotocol[i] := Char(ABytes[i+VIndex]);
|
|
end;
|
|
Inc(VIndex, Length(fprotocol));
|
|
end;
|
|
|
|
procedure ntlm_base.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32);
|
|
var
|
|
LLen : Integer;
|
|
LBytes : TIdBytes;
|
|
begin
|
|
inherited WriteStruct(VBytes,VIndex);
|
|
LBytes := System.Text.ASCIIEncoding.GetBytes(fprotocol);
|
|
LLen := Length(fprotocol);
|
|
CopyTIdBytes(LBytes, VIndex, VBytes, VIndex, LLen);
|
|
Inc(VIndex, LLen);
|
|
end;
|
|
|
|
function type_1_message_header.GetBytesLen: UInt32;
|
|
begin
|
|
Result := inherited GetByesLen() + 24;
|
|
end;
|
|
|
|
procedure type_1_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
inherited ReadStruct(ABytes, VIndex);
|
|
f_type := ABytes[VIndex];
|
|
Inc(VIndex);
|
|
BytesToByteArray(ABytes, fpad, VIndex);
|
|
Inc(VIndex, Length(fpad));
|
|
fflags := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
BytesToByteArray(ABytes, fpad2, VIndex);
|
|
Inc(VIndex, Length(fpad2));
|
|
fdom_len1 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fdom_len2 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fdom_off := BytesToUInt32(ABytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
fhost_len1 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fhost_len2 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fhost_off := BytesToUInt32(ABytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
end;
|
|
|
|
procedure type_1_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
inherited WriteStruct(VBytes, VIndex);
|
|
VBytes[VIndex] := f_type;
|
|
Inc(VIndex);
|
|
ByteArrayToBytes(fpad, VBytes, VIndex);
|
|
Inc(VIndex, Length(fpad));
|
|
CopyTIdUInt16(fflags, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
ByteArrayToBytes(fpad2, VBytes, VIndex);
|
|
Inc(VIndex, Length(fpad2));
|
|
CopyTIdUInt16(fdom_len1, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt16(fdom_len2, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt32(fdom_off, VBytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
CopyTIdUInt16(fhost_len1, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt16(fhost_len2, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt32(fhost_off, VBytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
end;
|
|
|
|
function type_2_message_header.GetBytesLen: UInt32;
|
|
begin
|
|
Result := inherited GetBytesLen() + 40;
|
|
end;
|
|
|
|
procedure type_2_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
inherited ReadStruct(ABytes, VIndex);
|
|
f_type := ABytes[VIndex];
|
|
Inc(VIndex);
|
|
BytesToByteArray(ABytes, fpad, VIndex);
|
|
Inc(VIndex, Length(fpad));
|
|
fhost_len1 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fhost_len2 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
fhost_off := BytesToUInt32(ABytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
fflags := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
BytesToByteArray(ABytes, fPad2, VIndex);
|
|
Inc(VIndex, Length(fpad2));
|
|
BytesToByteArray(ABytes, fnonce, VIndex);
|
|
Inc(VIndex, Length(fnonce));
|
|
BytesToByteArray(ABytes, freserved, VIndex);
|
|
Inc(VIndex, Length(freserved));
|
|
finfo_len1 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
finfo_len2 := BytesToUInt16(ABytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
finfo_off := BytesToUInt32(ABytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
end;
|
|
|
|
procedure type_2_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
inherited WriteStruct(VBytes, VIndex);
|
|
VBytes[VIndex] := f_type;
|
|
Inc(VIndex);
|
|
ByteArrayToBytes(fPad, VBytes, VIndex);
|
|
Inc(VIndex, Length(fpad));
|
|
CopyTIdUInt16(fhost_len1, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt16(fhost_len2, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt32(fhost_off, VBytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
CopyTIdUInt16(fflags, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
ByteArrayToBytes(fPad2, VBytes, VIndex);
|
|
Inc(VIndex, Length(fPad2));
|
|
ByteArrayToBytes(fnonce, VBytes, VIndex);
|
|
Inc(VIndex, Length(fnonce));
|
|
ByteArrayToBytes(freserved, VBytes, VIndex);
|
|
Inc(VIndex, Length(freserved));
|
|
CopyTIdUInt16(finfo_len1, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt16(finfo_len2, VBytes, VIndex);
|
|
Inc(VIndex, 2);
|
|
CopyTIdUInt32(finfo_off, VBytes, VIndex);
|
|
Inc(VIndex, 4);
|
|
end;
|
|
|
|
function type_3_message_header.GetBytesLen: UInt32;
|
|
begin
|
|
Result := inherited GetByteLen() + ? ;
|
|
end;
|
|
|
|
procedure type_3_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
{
|
|
_type: UInt32; // 0x03
|
|
|
|
lm_resp_len1: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_len2: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_off: UInt32; // LanManager response offset
|
|
|
|
nt_resp_len1: UInt16; // NT response length (always 0x18)
|
|
nt_resp_len2: UInt16; // NT response length (always 0x18)
|
|
nt_resp_off: UInt32; // NT response offset
|
|
|
|
dom_len1: UInt16; // domain string length
|
|
dom_len2: UInt16; // domain string length
|
|
dom_off: UInt32; // domain string offset (always 0x40)
|
|
|
|
user_len1: UInt16; // username string length
|
|
user_len2: UInt16; // username string length
|
|
user_off: UInt32; // username string offset
|
|
|
|
host_len1: UInt16; // host string length
|
|
host_len2: UInt16; // host string length
|
|
host_off: UInt32; // host string offset
|
|
zero: UInt32;
|
|
|
|
msg_len: UInt32; // message length
|
|
|
|
flags: UInt32; // 0xA0808205
|
|
}
|
|
end;
|
|
|
|
procedure type_3_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32);
|
|
begin
|
|
{
|
|
_type: UInt32; // 0x03
|
|
|
|
lm_resp_len1: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_len2: UInt16; // LanManager response length (always 0x18)
|
|
lm_resp_off: UInt32; // LanManager response offset
|
|
|
|
nt_resp_len1: UInt16; // NT response length (always 0x18)
|
|
nt_resp_len2: UInt16; // NT response length (always 0x18)
|
|
nt_resp_off: UInt32; // NT response offset
|
|
|
|
dom_len1: UInt16; // domain string length
|
|
dom_len2: UInt16; // domain string length
|
|
dom_off: UInt32; // domain string offset (always 0x40)
|
|
|
|
user_len1: UInt16; // username string length
|
|
user_len2: UInt16; // username string length
|
|
user_off: UInt32; // username string offset
|
|
|
|
host_len1: UInt16; // host string length
|
|
host_len2: UInt16; // host string length
|
|
host_off: UInt32; // host string offset
|
|
zero: UInt32;
|
|
|
|
msg_len: UInt32; // message length
|
|
|
|
flags: UInt32; // 0xA0808205
|
|
}
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
end.
|