| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749 |
- unit IdNTLMv2;
- interface
- {$i IdCompilerDefines.inc}
- uses
- IdGlobal,
- IdStruct
- {$IFNDEF DOTNET}, IdCTypes{$ENDIF}
- ;
- type
- ProtocolArray = array [ 1.. 8] of TIdAnsiChar;
- nonceArray = Array[ 1.. 8] of TIdAnsiChar;
- const
- //These are from:
- // http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
- // and the code is under a BSD license
- IdNTLMSSP_NEGOTIATE_UNICODE = $00000001; //A - NTLMSSP_NEGOTIATE_UNICODE
- IdNTLM_NEGOTIATE_OEM = $00000002; //B - NTLM_NEGOTIATE_OEM
- IdNTLMSSP_REQUEST_TARGET = $00000004; //C - NTLMSSP_REQUEST_TARGET
- IdNTLM_Unknown1 = $00000008; //r9 - should be zero
- IdNTLMSSP_NEGOTIATE_SIGN = $00000010; //D - NTLMSSP_NEGOTIATE_SIGN
- IdNTLMSSP_NEGOTIATE_SEAL = $00000020; //E - NTLMSSP_NEGOTIATE_SEAL
- IdNTLMSSP_NEGOTIATE_DATAGRAM = $00000040; //F - NTLMSSP_NEGOTIATE_DATAGRAM
- IdNTLMSSP_NEGOTIATE_LM_KEY = $00000080; //G - NTLMSSP_NEGOTIATE_LM_KEY
- //mentioned in http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
- //and http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
- //header. MS now says that is unused so it should be zero.
- IdNTLMSSP_NEGOTIATE_NETWARE = $00000100; //r8 - should be zero
- IdNTLMSSP_NEGOTIATE_NTLM = $00000200; //H - NTLMSSP_NEGOTIATE_NTLM
- IdNTLMSSP_NEGOTIATE_NT_ONLY = $00000400; //I - NTLMSSP_NEGOTIATE_NT_ONLY
- IdNTLMSSP_ANONYMOUS = $00000800; //J -
- IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = $00001000; //K - NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
- IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = $00002000; //L - NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
- //mentioned in http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
- //and http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
- //header. MS now says that is unused so it should be zero.
- IdNTLMSSP_NEGOTIATE_LOCAL_CALL = $00004000; //r6 - should be zero
- IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN = $00008000; //M - NTLMSSP_NEGOTIATE_ALWAYS_SIGN
- IdNTLMSSP_TARGET_TYPE_DOMAIN = $00010000; //N - NTLMSSP_TARGET_TYPE_DOMAIN
- IdNTLMSSP_TARGET_TYPE_SERVER = $00020000; //O - NTLMSSP_TARGET_TYPE_SERVER
- IdNTLMSSP_TARGET_TYPE_SHARE = $00040000; //P - NTLMSSP_TARGET_TYPE_SHARE
- IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = $00080000; //Q - NTLMSSP_NEGOTIATE_NTLM2
- //was NTLMSSP_REQUEST_INIT_RESPONSE 0x100000
- IdNTLMSSP_NEGOTIATE_IDENTIFY = $00100000; //R - NTLMSSP_NEGOTIATE_IDENTIFY
- IdNTLMSSP_REQUEST_ACCEPT_RESPONSE = $00200000; //r5 - should be zero
- //mentioned in http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
- //header. MS now says that is unused so it should be zero.
- IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY = $00400000; //S - NTLMSSP_REQUEST_NON_NT_SESSION_KEY
- IdNTLMSSP_NEGOTIATE_TARGET_INFO = $00800000; //T - NTLMSSP_NEGOTIATE_TARGET_INFO
- IdNTLM_Unknown4 = $01000000; //r4 - should be zero
- IdNTLMSSP_NEGOTIATE_VERSION = $02000000; //U - NTLMSSP_NEGOTIATE_VERSION
- // 400000
- IdNTLM_Unknown6 = $04000000; //r3 - should be zero
- IdNTLM_Unknown7 = $08000000; //r2 - should be zero
- IdNTLM_Unknown8 = $10000000; //r1 - should be zero
- IdNTLMSSP_NEGOTIATE_128 = $20000000; //V - NTLMSSP_NEGOTIATE_128
- IdNTLMSSP_NEGOTIATE_KEY_EXCH = $40000000; //W - NTLMSSP_NEGOTIATE_KEY_EXCH
- IdNTLMSSP_NEGOTIATE_56 = $80000000; //X - NTLMSSP_NEGOTIATE_56
- const
- //LC2 supports NTLMv2 only
- IdNTLM_TYPE1_FLAGS_LC2 = IdNTLMSSP_NEGOTIATE_UNICODE or
- IdNTLM_NEGOTIATE_OEM or
- IdNTLMSSP_REQUEST_TARGET or
- IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
- IdNTLM_TYPE1_FLAGS = IdNTLMSSP_NEGOTIATE_UNICODE or
- IdNTLM_NEGOTIATE_OEM or
- IdNTLMSSP_REQUEST_TARGET or
- IdNTLMSSP_NEGOTIATE_NTLM or
- // IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN or
- IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
- IdNTLM_TYPE1_MARKER : UInt32 = 1;
- IdNTLM_TYPE2_MARKER : UInt32 = 2;
- IdNTLM_TYPE3_MARKER : UInt32 = 3;
- IdNTLM_NTLMSSP_DES_KEY_LENGTH =7;
- IdNTLM_NTLMSSP_CHALLENGE_SIZE = 8;
- IdNTLM_LM_HASH_SIZE = 16;
- IdNTLM_LM_SESS_HASH_SIZE = 16;
- IdNTLM_LM_RESPONSE_SIZE = 24;
- IdNTLM_NTLMSSP_HASH_SIZE = 16;
- IdNTLM_NTLMSSP_RESPONSE_SIZE = 24;
- IdNTLM_NTLMSSP_V2_HASH_SIZE = 6;
- IdNTLM_NTLMSSP_V2_RESPONSE_SIZE = 16;
- IdNTLM_NONCE_LEN = 8;
- IdNTLM_TYPE2_TNAME_LEN_OFS = 12;
- IdNTLM_TYPE2_TNAME_OFFSET_OFS = 16;
- IdNTLM_TYPE2_FLAGS_OFS = 20;
- IdNTLM_TYPE2_NONCE_OFS = 24;
- IdNTLM_TYPE2_TINFO_LEN_OFS = 40;
- IdNTLM_TYPE2_TINFO_OFFSET_OFS = 44;
- IdNTLM_TYPE3_DOM_OFFSET = 64;
- //version info constants
- IdNTLM_WINDOWS_MAJOR_VERSION_5 = $05;
- IdNTLM_WINDOWS_MAJOR_VERSION_6 = $06;
- IdNTLM_WINDOWS_MINOR_VERSION_0 = $00;
- IdNTLM_WINDOWS_MINOR_VERSION_1 = $01;
- IdNTLM_WINDOWS_MINOR_VERSION_2 = $02;
- //original rel. build version of Vista
- //This isn't in the headers but I found easy enough.
- //It's provided because some NTLM servers might want ver info
- //from us. So we want to provide some dummy version and
- //Windows Vista is logical enough.
- IdNTLM_WINDOWS_BUILD_ORIG_VISTA = 6000;
- var
- IdNTLM_SSP_SIG : TIdBytes;
- UnixEpoch : TDateTime;
- {$DEFINE TESTSUITE}
- {$IFDEF TESTSUITE}
- procedure TestNTLM;
- {$ENDIF}
- function BuildType1Msg(const ADomain : String = ''; const AHost : String = ''; const ALMCompatibility : UInt32 = 0) : TIdBytes;
- procedure ReadType2Msg(const AMsg : TIdBytes; var VFlags : UInt32; var VTargetName : TIdBytes; var VTargetInfo : TIdBytes; var VNonce : TIdBytes );
- function BuildType3Msg(const ADomain, AHost, AUsername, APassword : String;
- const AFlags : UInt32; const AServerNonce : TIdBytes;
- const ATargetName, ATargetInfo : TIdBytes;
- const ALMCompatibility : UInt32 = 0) : TIdBytes;
- {
- function BuildType1Message( ADomain, AHost: String; const AEncodeMsg : Boolean = True): String;
- procedure ReadType2Message(const AMsg : String; var VNonce : nonceArray; var Flags : UInt32);
- function BuildType3Message( ADomain, AHost, AUsername: TIdUnicodeString; APassword : String; AServerNonce : nonceArray): String;
- }
- function NTLMFunctionsLoaded : Boolean;
- procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
- function DumpFlags(const ABytes : TIdBytes): String; overload;
- function DumpFlags(const AFlags : UInt32): String; overload;
- function LoadRC4 : Boolean;
- function RC4FunctionsLoaded : Boolean;
- implementation
- uses
- SysUtils,
- {$IFDEF USE_VCL_POSIX}
- PosixTime,
- {$ENDIF}
- {$IFDEF DOTNET}
- Classes,
- System.Runtime.InteropServices,
- System.Runtime.InteropServices.ComTypes,
- System.Security.Cryptography,
- System.Text,
- {$ELSE}
- {$IFDEF FPC}
- DynLibs, // better add DynLibs only for fpc
- {$ENDIF}
- {$IFDEF WINDOWS}
- //Windows should really not be included but this protocol does use
- //some windows internals and is Windows-based.
- Windows,
- {$ENDIF}
- {$ENDIF}
- IdFIPS,
- IdGlobalProtocols,
- IdHash,
- IdHMACMD5,
- IdHashMessageDigest,
- IdCoderMIME
- {$IFNDEF DOTNET}, IdSSLOpenSSLHeaders{$ENDIF} // TODO: remove dependency on this!
- ;
- const
- {$IFDEF DOTNET}
- MAGIC : array [ 0.. 7] of byte = ( $4b, $47, $53, $21, $40, $23, $24, $25);
- {$ELSE}
- Magic: des_cblock = ( $4B, $47, $53, $21, $40, $23, $24, $25 );
- Magic_const : array [0..7] of byte = ( $4b, $47, $53, $21, $40, $23, $24, $25 );
- {$ENDIF}
- TYPE1_MARKER = 1;
- TYPE2_MARGER = 2;
- TYPE3_MARKER = 3;
- //const
- // NUL_USER_SESSION_KEY : TIdBytes[0..15] = ($00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00);
- {$IFNDEF DOTNET}
- type
- Pdes_key_schedule = ^des_key_schedule;
- {$IFNDEF WINDOWS}
- FILETIME = record
- dwLowDateTime : UInt32;
- dwHighDateTime : UInt32;
- end;
- {$ENDIF}
- {$ENDIF}
- {$IFNDEF DOTNET}
- //const char *RC4_options(void);
- var
- GRC4_Options : function () : PIdAnsiChar; cdecl = nil;
- //void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
- GRC4_set_key : procedure(key : PRC4_KEY; len : TIdC_INT; data : PIdAnsiChar); cdecl = nil;
- //void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata,
- // unsigned char *outdata);
- GRC4 : procedure (key : PRC4_KEY; len : TIdC_ULONG; indata, outdata : PIdAnsiChar) ; cdecl = nil;
- {$ENDIF}
- function NulUserSessionKey : TIdBytes;
- begin
- SetLength(Result,16);
- FillChar(Result,16,0);
- end;
- //misc routines that might be helpful in some other places
- //===================
- {$IFDEF DOTNET}
- function Int64ToFileTime(const AInt64 : Int64) : System.Runtime.InteropServices.ComTypes.FILETIME;
- var
- LBytes : TIdBytes;
- begin
- LBytes := BitConverter.GetBytes(AInt64);
- Result.dwLowDateTime := BitConverter.ToInt32(Lbytes, 0);
- Result.dwHighDateTime := BitConverter.ToInt32(Lbytes, 4);
- end;
- function UnixTimeToFileTime(const AUnixTime : UInt32) : System.Runtime.InteropServices.ComTypes.FILETIME;
- {$ELSE}
- {
- We do things this way because in Win64, FILETIME may not be a simple typecast
- of Int64. It might be a two dword record that's aligned on an 8-byte
- boundery.
- }
- {$UNDEF USE_FILETIME_TYPECAST}
- {$IFDEF WINCE}
- {$DEFINE USE_FILETIME_TYPECAST}
- {$ENDIF}
- {$IFDEF WIN32}
- {$DEFINE USE_FILETIME_TYPECAST}
- {$ENDIF}
- function UnixTimeToFileTime(const AUnixTime : UInt32) : FILETIME;
- var
- i : Int64;
- {$ENDIF}
- begin
- {$IFDEF DOTNET}
- Result := Int64ToFileTime((AUnixTime + 11644473600) * 10000000);
- {$ELSE}
- i := (AUnixTime + 11644473600) * 10000000;
- {$IFDEF USE_FILETIME_TYPECAST}
- Result := FILETIME(i);
- {$ELSE}
- Result.dwLowDateTime := i and $FFFFFFFF;
- Result.dwHighDateTime := i shr 32;
- {$ENDIF}
- {$ENDIF}
- end;
- function NowAsFileTime : FILETIME;
- {$IFDEF DOTNET}
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- {$ENDIF}
- {$IFDEF UNIX}
- {$IFNDEF USE_VCL_POSIX}
- var
- TheTms: tms;
- {$ENDIF}
- {$ENDIF}
- begin
- {$IFDEF WINDOWS}
- {$IFDEF WINCE}
- // TODO
- {$ELSE}
- Windows.GetSystemTimeAsFileTime(Result);
- {$ENDIF}
- {$ENDIF}
- {$IFDEF UNIX}
- {$IFDEF USE_VCL_BASEUNIX}
- Result := UnixTimeToFileTime( fptimes (TheTms));
- {$ENDIF}
- //Is the following correct?
- {$IFDEF KYLIXCOMPAT}
- Result := UnixTimeToFileTime(Times(TheTms));
- {$ENDIF}
- {$IFDEF USE_VCL_POSIX}
- Result := UnixTimeToFileTime(PosixTime.time(nil));
- {$ENDIF}
- {$ENDIF}
- {$IFDEF DOTNET}
- Result := Int64ToFileTime(DateTime.Now.ToFileTimeUtc);
- // Result := System.DateTime.Now.Ticks;
- {$ENDIF}
- end;
- function ConcateBytes(const A1, A2 : TIdBytes) : TIdBytes;
- begin
- Result := A1;
- IdGlobal.AppendBytes(Result,A2);
- end;
- procedure CharArrayToBytes(const AArray : Array of char; var VBytes : TIdBytes; const AIndex : Integer=0);
- var
- i, ll, lh : Integer;
- begin
- ll := Low( AArray);
- lh := High( AArray);
- for i := ll to lh do begin
- VBytes[i] := Ord( AArray[ i]);
- end;
- end;
- 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;
- //---------------------------
- //end misc routines
- function DumpFlags(const ABytes : TIdBytes): String;
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- Result := DumpFlags( LittleEndianToHost(BytesToUInt32(ABytes)));
- end;
- function DumpFlags(const AFlags : UInt32): String;
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- Result := IntToHex(AFlags,8)+' -';
- if AFlags and IdNTLMSSP_NEGOTIATE_UNICODE <> 0 then
- begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_UNICODE';
- end;
- if AFlags and IdNTLM_NEGOTIATE_OEM <> 0 then begin
- Result := Result + ' IdNTLM_NEGOTIATE_OEM';
- end;
- if AFlags and IdNTLMSSP_REQUEST_TARGET <> 0 then begin
- Result := Result + ' IdNTLMSSP_REQUEST_TARGET';
- end;
- if AFlags and IdNTLM_Unknown1 <> 0 then begin
- Result := Result + ' IdNTLM_Unknown1';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_SIGN <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_SIGN';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_SEAL <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_SEAL';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_DATAGRAM <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_DATAGRAM';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_LM_KEY <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_LM_KEY';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_NETWARE <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_NETWARE';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_NTLM <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_NTLM';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_NT_ONLY';
- end;
- if AFlags and IdNTLMSSP_ANONYMOUS <> 0 then begin
- Result := Result + ' IdNTLMSSP_ANONYMOUS';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_LOCAL_CALL <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_LOCAL_CALL';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN';
- end;
- if AFlags and IdNTLMSSP_TARGET_TYPE_DOMAIN <> 0 then begin
- Result := Result + ' IdNTLMSSP_TARGET_TYPE_DOMAIN';
- end;
- if AFlags and IdNTLMSSP_TARGET_TYPE_SERVER <> 0 then begin
- Result := Result + ' IdNTLMSSP_TARGET_TYPE_SERVER';
- end;
- if AFlags and IdNTLMSSP_TARGET_TYPE_SHARE <> 0 then begin
- Result := Result + ' IdNTLMSSP_TARGET_TYPE_SHARE';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_IDENTIFY <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_IDENTIFY';
- end;
- if AFlags and IdNTLMSSP_REQUEST_ACCEPT_RESPONSE <> 0 then begin
- Result := Result + ' IdNTLMSSP_REQUEST_ACCEPT_RESPONSE';
- end;
- if AFlags and IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY <> 0 then begin
- Result := Result + ' IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_TARGET_INFO <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_TARGET_INFO';
- end;
- if AFlags and IdNTLM_Unknown4 <> 0 then begin
- Result := Result + ' IdNTLM_Unknown4';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_VERSION <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_VERSION';
- end;
- if AFlags and IdNTLM_Unknown8 <> 0 then begin
- Result := Result + ' IdNTLM_Unknown8';
- end;
- if AFlags and IdNTLM_Unknown7 <> 0 then begin
- Result := Result + ' IdNTLM_Unknown7';
- end;
- if AFlags and IdNTLM_Unknown8 <> 0 then begin
- Result := Result + ' IdNTLM_Unknown8';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_128 <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_128';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_KEY_EXCH <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_KEY_EXCH';
- end;
- if AFlags and IdNTLMSSP_NEGOTIATE_56 <> 0 then begin
- Result := Result + ' IdNTLMSSP_NEGOTIATE_56';
- end;
- end;
- {$IFDEF DOTNET}
- const
- DES_ODD_PARITY : array[ 0.. 255] of byte =
- ( 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
- 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
- 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
- 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
- 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
- 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
- 97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110,
- 112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127,
- 128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143,
- 145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158,
- 161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174,
- 176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191,
- 193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206,
- 208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223,
- 224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239,
- 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254);
- {
- IMPORTANT!!!
- In the NET framework, the DES API will not accept a weak key. Unfortunately,
- in NTLM's LM password, if a password is less than 8 charactors, the second key
- is weak. This is one flaw in that protocol.
- To workaround this, we use a precalculated key of zeros with the parity bit set
- and encrypt the MAGIC value with it. The Mono framework also does this.
- }
- const
- MAGIC_NUL_KEY : array [ 0.. 7] of byte = ($AA,$D3,$B4,$35,$B5,$14,$04,$EE);
- {barrowed from OpenSSL source-code - crypto/des/set_key.c 0.9.8g}
- {
- I barrowed it since it seems to work better than the NTLM sample code and because
- Microsoft.NET does not have this functionality when it really should have it.
- }
- procedure SetDesKeyOddParity(var VKey : TIdBytes);
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- i, l : Integer;
- begin
- l := Length( VKey);
- for i := 0 to l - 1 do begin
- VKey[ i] := DES_ODD_PARITY[ VKey[ i]];
- end;
- end;
- {$ENDIF}
- procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- i : Integer;
- begin
- {
- Can be like this:
- DOMAIN\user
- domain.com\user
- user@DOMAIN
- }
- i := IndyPos('\', AUsername);
- if i > 0 then begin //was -1
- VDomain := Copy( AUsername, 1, i - 1);
- VUserName := Copy( AUsername, i + 1, Length( AUserName));
- end else begin
- i := IndyPos('@',AUsername);
- if i > 0 then //was -1
- begin
- VUsername := Copy( AUsername, 1, i - 1);
- VDomain := Copy( AUsername, i + 1, Length( AUserName));
- end
- else
- begin
- VDomain := ''; {do not localize}
- VUserName := AUserName;
- end;
- end;
- end;
- {$IFDEF DOTNET}
- function NTLMFunctionsLoaded : Boolean;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- begin
- Result := True;
- end;
- {$ELSE}
- function NTLMFunctionsLoaded : Boolean;
- begin
- Result := LoadNTLMLibrary;
- if Result then begin
- Result := IsNTLMFuncsAvail;
- end;
- end;
- function LoadRC4 : Boolean;
- var
- h : Integer;
- begin
- Result := LoadNTLMLibrary;
- if Result then begin
- // TODO: move these into IndyTLSOpenSSL package and update IdFIPS unit...
- h := IdSSLOpenSSLHeaders.GetCryptLibHandle;
- GRC4_Options := LoadLibFunction(h,'RC4_options');
- GRC4_set_key := LoadLibFunction(h,'RC4_set_key');
- GRC4 := LoadLibFunction(h,'RC4');
- end;
- Result := RC4FunctionsLoaded;
- end;
- function RC4FunctionsLoaded : Boolean;
- begin
- // TODO: move these into IndyTLSOpenSSL package and update IdFIPS unit...
- // Result := IsNTLMv2FuncsAvail;
- Result := Assigned(GRC4_Options) and
- Assigned(GRC4_set_key) and
- Assigned(GRC4);
- end;
- {$ENDIF}
- //* create NT hashed password */
- function NTOWFv1(const APassword : String): TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- LHash: TIdHashMessageDigest4;
- begin
- CheckMD4Permitted;
- LHash := TIdHashMessageDigest4.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- Result := LHash.HashString(APassword, IndyTextEncoding_UTF16LE);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHash.Free;
- end;
- {$ENDIF}
- end;
- {$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);
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- 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;
- //Returns 8 bytes in length
- procedure _DES(var Res : TIdBytes; const Akey, AData : array of byte; const AKeyIdx, ADataIdx, AResIdx : Integer);
- var
- Lks: des_key_schedule;
- begin
- setup_des_key(pdes_cblock(@Akey[AKeyIdx])^, Lks);
- DES_ecb_encrypt(@AData[ADataIdx], Pconst_DES_cblock(@Res[AResIdx]), Lks, DES_ENCRYPT);
- end;
- function LMOWFv1(const Passwd, User, UserDom : TIdBytes) : TIdBytes;
- // ConcatenationOf( DES( UpperCase( Passwd)[0..6],"KGS!@#$%"),
- // DES( UpperCase( Passwd)[7..13],"KGS!@#$%"))
- var
- LBuf : TIdBytes;
- begin
- SetLength(Result,16);
- SetLength(LBuf,14);
- FillBytes( LBuf, 14, 0);
- CopyTIdBytes(Passwd,0,LBuf, 0,14);
- _DES(Result,LBuf, Magic_const,0,0,0);
- _DES(Result,LBuf, Magic_const,7,0,8);
- 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 DESL(const Akeys: TIdBytes; const AServerNonce: TIdBytes; out results: TIdBytes);
- //procedure DESL(keys: TIdBytes; AServerNonce: TIdBytes; results: TIdBytes);
- //procedure DESL(keys: TIdBytes; AServerNonce: TIdBytes; results: Pdes_key_schedule);
- var
- ks: des_key_schedule;
- begin
- SetLength(Results,24);
- setup_des_key(PDES_cblock(@Akeys[0])^, ks);
- DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(results), ks, DES_ENCRYPT);
- setup_des_key(PDES_cblock(Integer(Akeys) + 7)^, ks);
- DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(PtrUInt(results) + 8), ks, DES_ENCRYPT);
- setup_des_key(PDES_cblock(Integer(Akeys) + 14)^, ks);
- DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(PtrUInt(results) + 16), ks, DES_ENCRYPT);
- end;
- //* setup LanManager password */
- function SetupLMResponse(var vlmHash : TIdBytes; const APassword : String; AServerNonce : TIdBytes): TIdBytes;
- var
- lm_hpw : TIdBytes;
- lm_pw : TIdBytes;
- ks: des_key_schedule;
- begin
- SetLength( lm_hpw,21);
- FillBytes( lm_hpw, 14, 0);
- SetLength( lm_pw, 21);
- FillBytes( lm_pw, 14, 0);
- SetLength( vlmHash, 16);
- CopyTIdString( UpperCase( APassword), lm_pw, 0, 14);
- //* 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(@lm_pw[7])^, ks);
- DES_ecb_encrypt(@magic, pconst_des_cblock(@lm_hpw[8]), ks, DES_ENCRYPT);
- CopyTIdBytes(lm_pw,0,vlmHash,0,16);
- // FillChar(lm_hpw[17], 5, 0);
- SetLength(Result,24);
- DESL(lm_hpw, AServerNonce, Result);
- // DESL(PDes_cblock(@lm_hpw[0]), AServerNonce, Pdes_key_schedule(@Result[0]));
- //
- end;
- //* create NT hashed password */
- function CreateNTLMResponse(var vntlmhash : TIdBytes; const APassword : String; const nonce : TIdBytes): TIdBytes;
- var
- nt_pw : TIdBytes;
- nt_hpw : TIdBytes; //array [1..21] of Char;
- begin
- nt_pw := NTOWFv1(APassword);
- SetLength( nt_hpw, 21);
- FillChar( nt_hpw[ 17], 5, 0);
- CopyTIdBytes( nt_pw, 0, nt_hpw, 0, 16);
- // done in DESL
- SetLength( Result, 24);
- // DESL(pdes_cblock(@nt_hpw[0]), nonce, Pdes_key_schedule(@Result[0]));
- DESL(nt_hpw, nonce, Result);
- end;
- {
- function CreateNTLMResponse(const APassword : String; const nonce : TIdBytes): TIdBytes;
- var
- nt_pw : TIdBytes;
- nt_hpw : array [ 1.. 21] of AnsiChar;
- LHash: TIdHashMessageDigest4;
- begin
- nt_pw := NTOWFv1(APassword);
- SetLength(Result,24);
- Move( nt_pw[ 0], nt_hpw[ 1], 16);
- FillChar( nt_hpw[ 17], 5, 0);
- DESL(pdes_cblock( @nt_hpw[1]), nonce, Pdes_key_schedule( @Result[ 0]));
- end;
- }
- {$ELSE}
- procedure setup_des_key(const Akey_56: TIdBytes; out Key : TIdBytes; const AIndex : Integer = 0);
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- SetLength( key, 8);
- key[0] := Akey_56[ AIndex];
- key[1] := (( Akey_56[ AIndex] SHL 7) and $FF) or (Akey_56[ AIndex + 1] SHR 1);
- key[2] := (( Akey_56[ AIndex + 1] SHL 6) and $FF) or (Akey_56[ AIndex + 2] SHR 2);
- key[3] := (( Akey_56[ AIndex + 2] SHL 5) and $FF) or (Akey_56[ AIndex + 3] SHR 3);
- key[4] := (( Akey_56[ AIndex + 3] SHL 4) and $FF) or (Akey_56[ AIndex + 4] SHR 4);
- key[5] := (( Akey_56[ AIndex + 4] SHL 3) and $FF) or (Akey_56[ AIndex + 5] SHR 5);
- key[6] := (( Akey_56[ AIndex + 5] SHL 2) and $FF) or (Akey_56[ AIndex + 6] SHR 6);
- key[7] := ( AKey_56[ AIndex + 6] SHL 1) and $FF;
- SetDesKeyOddParity( Key);
- end;
- procedure DESL(const Akeys: TIdBytes; const AServerNonce: TIdBytes; out results: TIdBytes);
- var
- LKey : TIdBytes;
- LDes : System.Security.Cryptography.DES;
- LEnc : ICryptoTransform;
- begin
- SetLength( Results, 24);
- SetLength( LKey, 8);
- LDes := DESCryptoServiceProvider.Create;
- LDes.Mode := CipherMode.ECB;
- LDes.Padding := PaddingMode.None;
- setup_des_key( AKeys, LKey, 0);
- LDes.Key := LKey;
- LEnc := LDes.CreateEncryptor;
- LEnc.TransformBlock( AServerNonce, 0, 8, Results, 0);
- setup_des_key( AKeys, LKey, 7);
- LDes.Key := LKey;
- LEnc := LDes.CreateEncryptor;
- LEnc.TransformBlock( AServerNonce, 0, 8, Results, 8);
- setup_des_key(AKeys,LKey,14);
- LDes.Key := LKey;
- LEnc := LDes.CreateEncryptor;
- LEnc.TransformBlock( AServerNonce, 0, 8, Results, 16);
- end;
- function SetupLMResponse(const APassword : String; AServerNonce : TIdBytes): TIdBytes;
- var
- lm_hpw : TIdBytes; //array[1..21] of Char;
- lm_pw : TIdBytes; //array[1..21] of Char;
- LDes : System.Security.Cryptography.DES;
- LEnc : ICryptoTransform;
- LKey : TIdBytes;
- begin
- SetLength( lm_hpw,21);
- FillBytes( lm_hpw, 14, 0);
- SetLength( lm_pw, 21);
- FillBytes( lm_pw, 14, 0);
- CopyTIdString( UpperCase( APassword), lm_pw, 0, 14);
- LDes := DESCryptoServiceProvider.Create;
- LDes.Mode := CipherMode.ECB;
- LDes.Padding := PaddingMode.None;
- setup_des_key( lm_pw, LKey, 0);
- LDes.BlockSize := 64;
- LDes.Key := LKey;
- LEnc := LDes.CreateEncryptor;
- LEnc.TransformBlock( MAGIC, 0, 8, lm_hpw, 0);
- setup_des_key( lm_pw, LKey,7);
- if Length( APassword) > 7 then begin
- LDes.Key := LKey;
- LEnc := LDes.CreateEncryptor;
- LEnc.TransformBlock( MAGIC, 0, 8, lm_hpw, 8);
- end else begin
- CopyTIdBytes( MAGIC_NUL_KEY, 0, lm_hpw, 8, 8);
- end;
- DESL( lm_hpw, nonce, Result);
- end;
- function CreateNTLMResponse(const APassword : String; const nonce : TIdBytes): TIdBytes;
- var
- nt_pw : TIdBytes;
- nt_hpw : TIdBytes; //array [1..21] of Char;
- nt_hpw128 : TIdBytes;
- begin
- CheckMD4Permitted;
- nt_pw := System.Text.Encoding.Unicode.GetBytes( APassword);
- with TIdHashMessageDigest4.Create do try
- nt_hpw128 := HashString( nt_pw);
- finally
- Free;
- end;
- SetLength( nt_hpw, 21);
- FillBytes( nt_hpw, 21, 0);
- CopyTIdBytes( nt_hpw128, 0, nt_hpw, 0, 16);
- // done in DESL
- //SetLength( nt_resp, 24);
- DESL( nt_hpw,nonce, Result);
- end;
- {$ENDIF}
- procedure AddUInt16(var VBytes: TIdBytes; const AWord : UInt16);
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- var
- LBytes : TIdBytes;
- begin
- SetLength(LBytes,SizeOf(AWord));
- CopyTIdUInt16(HostToLittleEndian(AWord),LBytes,0);
- AppendBytes( VBytes,LBytes);
- end;
- procedure AddUInt32(var VBytes: TIdBytes; const ALongWord : UInt32);
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- var
- LBytes : TIdBytes;
- begin
- SetLength(LBytes,SizeOf(ALongWord));
- CopyTIdUInt32(HostToLittleEndian(ALongWord),LBytes,0);
- AppendBytes( VBytes,LBytes);
- end;
- procedure AddInt64(var VBytes: TIdBytes; const AInt64 : Int64);
- var
- LBytes : TIdBytes;
- begin
- SetLength(LBytes,SizeOf(AInt64));
- {$IFDEF ENDIAN_LITTLE}
- IdGlobal.CopyTIdInt64(AInt64,LBytes,0);
- {$ELSE}
- //done this way since we need this in little endian byte-order
- CopyTIdUInt32(HostToLittleEndian(Lo( AInt64)));
- CopyTIdUInt32(HostToLittleEndian(Hi( AInt64)));
- {$ENDIF}
- AppendBytes( VBytes,LBytes);
- end;
- {
- IMPORTANT!!! I think the time feilds in the NTLM blob are really FILETIME
- records.
- MSDN says that a Contains a 64-bit value representing the number of
- 100-nanosecond intervals since January 1, 1601 (UTC).
- http://davenport.sourceforge.net/ntlm.html says that the time feild is
- Little-endian, 64-bit signed value representing the number of tenths of a
- microsecond since January 1, 1601.
- In other words, they are the same. We use FILETIME for the API so that
- we can easily obtain a the timestamp for the blob in Microsoft.NET as well as
- Delphi (the work on proper format is already done for us.
- }
- const
- NTLMv2_BLOB_Sig : array [0..3] of byte = ($01,$01,$00,$00);
- NTLMv2_BLOB_Res : array [0..3] of byte = ($00,$00,$00,$00);
- function IndyByteArrayLength(const ABuffer: array of byte; const ALength: Integer = -1; const AIndex: Integer = 0): Integer;
- var
- LAvailable: Integer;
- begin
- Assert(AIndex >= 0);
- LAvailable := IndyMax(Length(ABuffer)-AIndex, 0);
- if ALength < 0 then begin
- Result := LAvailable;
- end else begin
- Result := IndyMin(LAvailable, ALength);
- end;
- end;
- procedure AddByteArray(var VBytes : TIdBytes; const AToAdd : array of byte; const AIndex: Integer = 0);
- var
- LOldLen, LAddLen : Integer;
- begin
- LAddLen := IndyByteArrayLength(AToAdd, -1, AIndex);
- if LAddLen > 0 then begin
- LOldLen := Length(VBytes);
- SetLength(VBytes, LOldLen + LAddLen);
- CopyTIdByteArray(AToAdd, AIndex, VBytes, LOldLen, LAddLen);
- end;
- end;
- {$IFDEF DOTNET}
- function MakeBlob(const ANTLMTimeStamp : System.Runtime.InteropServices.ComTypes.FileTime;
- const ATargetInfo : TIdBytes;const cnonce : TIdBytes) : TIdBytes;
- {$ELSE}
- function MakeBlob(const ANTLMTimeStamp : FILETIME; const ATargetInfo : TIdBytes;const cnonce : TIdBytes) : TIdBytes;
- {$ENDIF}
- begin
- SetLength(Result,0);
- //blob signature - offset 0
- // RespType - offset 0
- // HiRespType - offset 1
- // Reserved1 - offset 2
- AddByteArray( Result, NTLMv2_BLOB_Sig);
- // reserved - offset 4
- // Reserved2 - offset 4
- AddByteArray( Result, NTLMv2_BLOB_Res);
- // time - offset 8
- IdNTLMv2.AddUInt32(Result, ANTLMTimeStamp.dwLowDateTime );
- IdNTLMv2.AddUInt32(Result, ANTLMTimeStamp.dwHighDateTime );
- //client nonce (challange)
- // cnonce - offset 16
- IdGlobal.AppendBytes(Result,cnonce);
- // reserved 3
- // offset - offset 24
- AddUInt32(Result,0);
- // AddByteArray( Result, NTLMv2_BLOB_Res);
- // targetinfo - offset 28
- // av pairs - offset 28
- IdGlobal.AppendBytes(Result,ATargetInfo);
- // unknown (0 works)
- AddByteArray( Result, NTLMv2_BLOB_Res);
- end;
- function InternalCreateNTLMv2Response(var Vntlm2hash : TIdBytes;
- const AUsername, ADomain, APassword : String;
- const ATargetInfo : TIdBytes;
- const ATimestamp : FILETIME;
- const cnonce, nonce : TIdBytes): TIdBytes;
- var
- LLmUserDom : TIdBytes;
- Blob : TIdBytes;
- LEncoding: IIdTextEncoding;
- LHMac: TIdHMACMD5;
- begin
- LEncoding := IndyTextEncoding_UTF16LE;
- LLmUserDom := LEncoding.GetBytes(UpperCase(AUsername));
- AppendBytes(LLmUserDom, LEncoding.GetBytes(ADomain));
- LEncoding := nil;
- LHMac := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHMac.Key := NTOWFv1(APassword);
- Vntlm2hash := LHMac.HashValue(LLmUserDom);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHMac.Free;
- end;
- {$ENDIF}
- Blob := MakeBlob(ATimestamp,ATargetInfo,cnonce);
- LHMac := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHMac.Key := Vntlm2hash;
- Result := LHMac.HashValue(ConcateBytes(nonce,Blob));
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHMac.Free;
- end;
- {$ENDIF}
- AppendBytes(Result,Blob);
- end;
- function CreateNTLMv2Response(var Vntlm2hash : TIdBytes;
- const AUsername, ADomain, APassword : String;
- const TargetName, ATargetInfo : TIdBytes;
- const cnonce, nonce : TIdBytes): TIdBytes;
- begin
- Result := InternalCreateNTLMv2Response(Vntlm2hash, AUsername, ADomain, APassword, ATargetInfo, NowAsFileTime,cnonce, nonce);
- end;
- function LMUserSessionKey(const AHash : TIdBytes) : TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- // 1. The 16-byte LM hash (calculated previously) is truncated to 8 bytes.
- // 2. This is null-padded to 16 bytes. This value is the LM User Session Key.
- begin
- SetLength(Result,16);
- FillBytes(Result,16,0);
- CopyTIdBytes(AHash,0,Result,0,8);
- end;
- function UserNTLMv1SessionKey(const AHash : TIdBytes) : TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- LHash: TIdHashMessageDigest4;
- begin
- CheckMD4Permitted;
- LHash := TIdHashMessageDigest4.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- Result := LHash.HashBytes(AHash);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHash.Free;
- end;
- {$ENDIF}
- end;
- function UserLMv2SessionKey(const AHash : TIdBytes; const ABlob : TIdBytes; ACNonce : TIdBytes) : TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- LBuf : TIdBytes;
- LHMac: TIdHMACMD5;
- begin
- LBuf := ABlob;
- AppendBytes(LBuf,ACNonce);
- LHMac := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHMac.Key := AHash;
- Result := LHMac.HashValue(LHMac.HashValue(LBuf));
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHMac.Free;
- end;
- {$ENDIF}
- end;
- function UserNTLMv2SessionKey(const AHash : TIdBytes; const ABlob : TIdBytes; const AServerNonce : TIdBytes) : TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- //extremely similar to the above except that the nonce is used.
- begin
- Result := UserLMv2SessionKey(AHash,ABlob,AServerNonce);
- end;
- function UserNTLM2SessionSecSessionKey(const ANTLMv1SessionKey : TIdBytes; const AServerNonce : TIdBytes): TIdBytes;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- var
- LHash: TIdHMACMD5;
- begin
- LHash := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHash.Key := ANTLMv1SessionKey;
- Result := LHash.HashValue(AServerNonce);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHash.Free;
- end;
- {$ENDIF}
- end;
- function LanManagerSessionKey(const ALMHash : TIdBytes) : TIdBytes;
- var
- LKey : TIdBytes;
- ks : des_key_schedule;
- LHash8 : TIdBytes;
- begin
- LHash8 := ALMHash;
- SetLength(LHash8,8);
- SetLength(LKey,14);
- FillChar(LKey,14,$bd);
- CopyTIdBytes(LHash8,0,LKey,0,8);
- SetLength(Result,16);
- setup_des_key(pdes_cblock(@LKey[0])^, ks);
- DES_ecb_encrypt(@LHash8, pconst_des_cblock(@Result[0]), ks, DES_ENCRYPT);
- setup_des_key(pdes_cblock(@LKey[7])^, ks);
- DES_ecb_encrypt(@LHash8, pconst_des_cblock(@Result[8]), ks, DES_ENCRYPT);
- end;
- function SetupLMv2Response(var VntlmHash : TIdBytes; const AUsername, ADomain : String; const APassword : String; cnonce, AServerNonce : TIdBytes): TIdBytes;
- var
- LLmUserDom : TIdBytes;
- LChall : TIdBytes;
- LEncoding: IIdTextEncoding;
- LHMac: TIdHMACMD5;
- begin
- LEncoding := IndyTextEncoding_UTF16LE;
- LLmUserDom := LEncoding.GetBytes(UpperCase(AUsername));
- AppendBytes(LLmUserDom, LEncoding.GetBytes(ADomain));
- LEncoding := nil;
- LHMac := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHMac.Key := NTOWFv1(APassword);
- VntlmHash := LHMac.HashValue(LLmUserDom);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHMac.Free;
- end;
- {$ENDIF}
- LChall := AServerNonce;
- IdGlobal.AppendBytes(LChall,cnonce);
- LHMac := TIdHMACMD5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- LHMac.Key := vntlmhash;
- Result := LHMac.HashValue(LChall);
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHMac.Free;
- end;
- {$ENDIF}
- AppendBytes(Result,cnonce);
- end;
- //function SetupLMResponse(const APassword : String; nonce : TIdBytes): TIdBytes;
- function CreateModNTLMv1Response(var Vntlmseshash : TIdBytes; const AUsername : String; const APassword : String; cnonce, nonce : TIdBytes; var LMFeild : TIdBytes): TIdBytes;
- var
- LChall, LTmp : TIdBytes;
- lntlmseshash : TIdBytes;
- LPassHash : TIdBytes;
- LHash: TIdHashMessageDigest5;
- begin
- CheckMD5Permitted;
- //LM feild value for Type3 message
- SetLength(LMFeild,24);
- FillBytes( LMFeild,24, 0);
- IdGlobal.CopyTIdBytes(cnonce,0,LMFeild,0,8);
- //
- LChall := nonce;
- IdGlobal.AppendBytes(LChall,cnonce);
- LHash := TIdHashMessageDigest5.Create;
- {$IFNDEF USE_OBJECT_ARC}
- try
- {$ENDIF}
- Vntlmseshash := LHash.HashBytes(LChall);
- //we do this copy because we may need the value later.
- lntlmseshash := Vntlmseshash;
- {$IFNDEF USE_OBJECT_ARC}
- finally
- LHash.Free;
- end;
- {$ENDIF}
- SetLength(lntlmseshash,8);
- SetLength(LPassHash,21);
- FillBytes( LPassHash,21, 0);
- LTmp := NTOWFv1(APassword);
- IdGlobal.CopyTIdBytes(LTmp,0,LPassHash,0,Length(LTmp));
- {$IFNDEF DOTNET}
- SetLength(Result,24);
- DESL( LPassHash,lntlmseshash, Result);
- // DESL(PDes_cblock(@LPassHash[0]), lntlmseshash, Pdes_key_schedule(@Result[0]));
- {$ELSE}
- DESL( LPassHash,ntlmseshash, Result);
- {$ENDIF}
- end;
- //Todo: This does not match the results from
- //http://davenport.sourceforge.net/ntlm.html
- function TDateTimeToNTLMTime(const ADateTime : TDateTime):Int64;
- {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- Result := DateTimeToUnix((ADateTime+11644473600)* 10000);
- end;
- function BuildType1Msg(const ADomain : String = ''; const AHost : String = ''; const ALMCompatibility : UInt32 = 0) : TIdBytes;
- var
- LDomain, LWorkStation: TIdBytes;
- LDomLen, LWorkStationLen: UInt16;
- LFlags : UInt32;
- LEncoding: IIdTextEncoding;
- begin
- SetLength(Result,0);
- LEncoding := IndyTextEncoding_OSDefault;
- LDomain := LEncoding.GetBytes(ADomain); //UpperCase(ADomain));
- LWorkStation := LEncoding.GetBytes(AHost); //UpperCase(AHost));
- LEncoding := nil;
- LFlags := IdNTLM_TYPE1_FLAGS_LC2;
- case ALMCompatibility of
- 0, 1 : LFlags := IdNTLM_TYPE1_FLAGS;
- end;
- LDomLen := Length(LDomain);
- if LDomLen > 0 then begin
- LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
- end;
- LWorkStationLen := Length(LWorkStation);
- if LWorkStationLen > 0 then begin
- LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
- end;
- //signature
- AppendBytes(Result,IdNTLM_SSP_SIG);
- //type
- AddUInt32(Result,IdNTLM_TYPE1_MARKER);
- //flags
- AddUInt32(Result,LFlags);
- //Supplied Domain security buffer
- // - length
- AddUInt16(Result,LDomLen);
- // - allocated space
- AddUInt16(Result,LDomLen);
- // - offset
- AddUInt32(Result,LWorkStationLen+$20);
- //Supplied Workstation security buffer (host)
- // - length
- AddUInt16(Result,LWorkStationLen);
- // - allocated space
- AddUInt16(Result,LWorkStationLen);
- // - offset
- if LWorkStationLen > 0 then begin
- AddUInt32(Result,$20);
- end else begin
- AddUInt32(Result,$08);
- end;
- // Supplied Workstation (host)
- if LWorkStationLen > 0 then begin
- AppendBytes(Result,LWorkStation,0,LWorkStationLen);
- end;
- // Supplied Domain
- if LDomLen > 0 then begin
- AppendBytes(Result,LDomain,0,LDomLen);
- end;
- end;
- procedure ReadType2Msg(const AMsg : TIdBytes; var VFlags : UInt32; var VTargetName : TIdBytes; var VTargetInfo : TIdBytes; var VNonce : TIdBytes );
- var
- LLen : UInt16;
- LOfs : UInt32;
- begin
- //extract flags
- VFlags := LittleEndianToHost(BytesToUInt32(AMsg,IdNTLM_TYPE2_FLAGS_OFS));
- //extract target name
- // - security buffer
- LLen := LittleEndianToHost( BytesToUInt16(AMsg,IdNTLM_TYPE2_TNAME_LEN_OFS));
- LOfs := LittleEndianToHost( BytesToUInt32(AMsg,IdNTLM_TYPE2_TNAME_OFFSET_OFS));
- // - the buffer itself
- SetLength(VTargetName,LLen);
- CopyTIdBytes(AMsg,LOfs,VTargetName,0,LLen);
- //extract targetinfo
- //Note that we should ignore TargetInfo if it is not required.
- if VFlags and IdNTLMSSP_NEGOTIATE_TARGET_INFO > 0 then begin
- // - security buffer
- LLen := LittleEndianToHost( BytesToUInt16(AMsg,IdNTLM_TYPE2_TINFO_LEN_OFS));
- LOfs := LittleEndianToHost( BytesToUInt32(AMsg,IdNTLM_TYPE2_TINFO_OFFSET_OFS));
- // - the buffer itself
- SetLength(VTargetInfo,LLen);
- CopyTIdBytes(AMsg,LOfs,VTargetInfo,0,LLen);
- end else begin
- SetLength(VTargetInfo,0);
- end;
- //extract nonce
- SetLength(VNonce,IdNTLM_NONCE_LEN);
- CopyTIdBytes(AMsg,IdNTLM_TYPE2_NONCE_OFS,VNonce,0,IdNTLM_NONCE_LEN);
- end;
- function CreateData(const ABytes : TIdBytes; const AOffset : UInt32; var VBuffer : TIdBytes) : UInt32;
- //returns the next buffer value
- //adds security value ptr to Vbuffer
- var
- LLen : UInt16;
- begin
- LLen := Length(ABytes);
- // - length
- AddUInt16(VBuffer,LLen);
- // - allocated space
- AddUInt16(VBuffer,LLen);
- // - offset
- AddUInt32(VBuffer,AOffset);
- Result := AOffset + Llen;
- end;
- function GenerateCNonce : TIdBytes;
- begin
- SetLength(Result,8);
- Randomize;
- Result[0] := Random(127)+1;
- Result[1] := Random(127)+1;
- Result[2] := Random(127)+1;
- Result[3] := Random(127)+1;
- Result[4] := Random(127)+1;
- Result[5] := Random(127)+1;
- Result[6] := Random(127)+1;
- Result[7] := Random(127)+1;
- end;
- const
- IdNTLM_IGNORE_TYPE_2_3_MASK = not
- (IdNTLMSSP_TARGET_TYPE_DOMAIN or
- IdNTLMSSP_TARGET_TYPE_SERVER or
- IdNTLMSSP_TARGET_TYPE_SHARE);
- function BuildType3Msg(const ADomain, AHost, AUsername, APassword : String;
- const AFlags : UInt32; const AServerNonce : TIdBytes;
- const ATargetName, ATargetInfo : TIdBytes;
- const ALMCompatibility : UInt32 = 0) : TIdBytes;
- var
- LDom, LHost, LUser, LLMData, LNTLMData, LCNonce : TIdBytes;
- llmhash, lntlmhash : TIdBytes;
- ll_len, ln_len, ld_len, lh_len, lu_len : UInt16;
- ll_ofs, ln_ofs, ld_ofs, lh_ofs, lu_ofs : UInt32;
- LFlags : UInt32;
- LEncoding: IIdTextEncoding;
- begin
- LFlags := AFlags and IdNTLM_IGNORE_TYPE_2_3_MASK;
- if AFlags and IdNTLMSSP_REQUEST_TARGET > 0 then begin
- LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
- end;
- if LFlags and IdNTLMSSP_NEGOTIATE_UNICODE <> 0 then begin
- LEncoding := IndyTextEncoding_UTF16LE;
- if LFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED > 0 then begin
- if Length(ATargetName) > 0 then begin
- LDom := ATargetName;
- end else begin
- LDom := LEncoding.GetBytes(UpperCase(ADomain));
- end;
- end;
- if LFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED > 0 then begin
- LHost := LEncoding.GetBytes(UpperCase(AHost));
- end;
- LUser := LEncoding.GetBytes(UpperCase(AUsername));
- LEncoding := nil;
- end else begin
- if LFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED > 0 then begin
- LDom := ToBytes(UpperCase(ADomain));
- end;
- if LFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED > 0 then begin
- LHost := ToBytes(UpperCase(AHost));
- end;
- LUser := ToBytes(UpperCase(AUsername));
- end;
- if (ALMCompatibility < 3) and
- (AFlags and IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY > 0) then
- begin
- LCNonce := GenerateCNonce;
- LNTLMData := CreateModNTLMv1Response(lntlmhash,AUserName,APassword,LCNonce,AServerNonce,LLMData);
- // LLMData := IdNTLMv2.SetupLMv2Response(AUsername,ADomain,APassword,LCNonce,AServerNonce);
- // LNTLMData := CreateNTLMv2Response(AUserName,ADomain,APassword,ATargetName,ATargetName, ATargetInfo,LCNonce);
- end else begin
- case ALMCompatibility of
- 0 :
- begin
- if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
- begin
- SetLength(LLMData,0);
- end
- else
- begin
- LLMData := SetupLMResponse(llmhash, APassword, AServerNonce);
- end;
- LNTLMData := CreateNTLMResponse(lntlmhash, APassword, AServerNonce);
- end;
- 1 :
- begin
- if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
- begin
- SetLength(LLMData,0);
- end
- else
- begin
- LLMData := SetupLMResponse(llmhash, APassword, AServerNonce);
- end;
- LNTLMData := CreateNTLMResponse(lntlmhash,APassword, AServerNonce);
- end;
- 2 : //Send NTLM response only
- begin
- LNTLMData := CreateNTLMResponse(lntlmhash,APassword, AServerNonce);
- if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
- begin
- SetLength(LLMData,0);
- end
- else
- begin
- LLMData := LNTLMData;
- // LLMData := SetupLMResponse(APassword, ANonce);
- end;
- end;
- 3,4,5 : //Send NTLMv2 response only
- begin
- // LFlags := LFlags and (not IdNTLMSSP_NEGOTIATE_NTLM);
- LCNonce := GenerateCNonce;
- LLMData := IdNTLMv2.SetupLMv2Response(llmhash,AUsername,ADomain,APassword,LCNonce,AServerNonce);
- LNTLMData := CreateNTLMv2Response(lntlmhash,AUserName,ADomain,APassword,ATargetName,ATargetInfo,LCNonce,AServerNonce);
- end;
- // LCNonce := GenerateCNonce;
- // LNTLMData := IdNTLMv2.CreateModNTLMv1Response(AUserName,APassword,LCNonce,ANonce,LLMData);
- end;
- end;
- //calculations for security buffer pointers
- //We do things this way because the security buffers are in a different order
- //than the data buffers themselves. In theory, you could change it but it's
- //not a good idea.
- ll_len := Length(LLMData);
- ln_len := Length(LNTLMData);
- ld_len := Length(LDom);
- lh_len := Length(LHost);
- lu_len := Length(LUser);
- LFlags := LFlags and (not IdNTLMSSP_NEGOTIATE_VERSION);
- ld_ofs := IdNTLM_TYPE3_DOM_OFFSET;
- { if LFlags and IdNTLMSSP_NEGOTIATE_VERSION <> 0 then
- begin
- ld_ofs := IdNTLM_TYPE3_DOM_OFFSET + 8;
- AppendByte(Result, IdNTLM_WINDOWS_MAJOR_VERSION_6);
- AppendByte(Result, IdNTLM_WINDOWS_MINOR_VERSION_0);
- AddUInt16(Result,IdNTLM_WINDOWS_BUILD_ORIG_VISTA);
- AddUInt32(Result,$F);
- end; }
- lu_ofs := ld_len + ld_ofs;
- lh_ofs := lu_len + lu_ofs;
- ll_ofs := lh_len + lh_ofs;
- ln_ofs := ll_len + ll_ofs;
- SetLength(Result,0);
- // 0 - signature
- AppendBytes(Result,IdNTLM_SSP_SIG);
- // 8 - type
- AddUInt32(Result,IdNTLM_TYPE3_MARKER);
- //12 - LM Response Security Buffer:
- // - length
- AddUInt16(Result,ll_len);
- // - allocated space
- AddUInt16(Result,ll_len);
- // - offset
- AddUInt32(Result,ll_ofs);
- //20 - NTLM Response Security Buffer:
- // - length
- AddUInt16(Result,ln_len);
- // - allocated space
- AddUInt16(Result,ln_len);
- // - offset
- AddUInt32(Result,ln_ofs);
- //28 - Domain Name Security Buffer: (target)
- // - length
- AddUInt16(Result,ld_len);
- // - allocated space
- AddUInt16(Result,ld_len);
- // - offset
- AddUInt32(Result,ld_ofs);
- //36 - User Name Security Buffer:
- // - length
- AddUInt16(Result,lu_len);
- // - allocated space
- AddUInt16(Result,lu_len);
- // - offset
- AddUInt32(Result,lu_ofs);
- //44 - Workstation Name (host) Security Buffer:
- // - length
- AddUInt16(Result,lh_len);
- // - allocated space
- AddUInt16(Result,lh_len);
- // - offset
- AddUInt32(Result,lh_ofs);
- //52 - Session Key Security Buffer:
- // - length
- AddUInt16(Result,0);
- // - allocated space
- AddUInt16(Result,0);
- // - offset
- AddUInt32(Result,ln_ofs+ln_len);
- //60 - Flags:
- //The flags feild is strictly optional. About the only time it matters is
- //with Datagram authentication.
- AddUInt32(Result,LFlags);
- if ld_len > 0 then
- begin
- //64 - Domain Name Data ("DOMAIN")
- AppendBytes(Result,LDom);
- end;
- if lu_len >0 then
- begin
- //User Name Data ("user")
- AppendBytes(Result,LUser);
- end;
- if lh_len > 0 then
- begin
- //Workstation Name Data (host)
- AppendBytes(Result,LHost);
- end;
- //LM Response Data
- AppendBytes(Result,LLMData);
- //NTLM Response Data
- AppendBytes(Result,LNTLMData);
- end;
- {$IFDEF TESTSUITE}
- const
- TEST_TARGETINFO : array [0..97] of byte = (
- $02,$00,$0c,$00,$44,$00,$4f,$00,
- $4d,$00,$41,$00,$49,$00,$4e,$00,
- $01,$00,$0c,$00,$53,$00,$45,$00,
- $52,$00,$56,$00,$45,$00,$52,$00,
- $04,$00,$14,$00,$64,$00,$6f,$00,
- $6d,$00,$61,$00,$69,$00,$6e,$00,
- $2e,$00,$63,$00,$6f,$00,$6d,$00,
- $03,$00,$22,$00,$73,$00,$65,$00,
- $72,$00,$76,$00,$65,$00,$72,$00,
- $2e,$00,$64,$00,$6f,$00,$6d,$00,
- $61,$00,$69,$00,$6e,$00,$2e,$00,
- $63,$00,$6f,$00,$6d,$00,$00,$00,
- $00,$00);
- {function StrToHex(const AStr : AnsiString) : AnsiString;
- var
- i : Integer;
- begin
- Result := '';
- for i := 1 to Length(AStr) do begin
- Result := Result + IntToHex(Ord(AStr[i]),2)+ ' ';
- end;
- end; }
- function BytesToHex(const ABytes : array of byte) : String;
- var
- i : Integer;
- begin
- for i := Low(ABytes) to High(ABytes) do
- begin
- Result := Result + IntToHex(ABytes[i],2)+ ' ';
- end;
- end;
- procedure DoDavePortTests;
- var
- LNonce,LCNonce, lmhash : TIdBytes;
- LMResp : TIdBytes;
- LTargetINfo : TIdBytes;
- Ltst : String;
- begin
- SetLength(LNonce,8);
- LNonce[0] := $01;
- LNonce[1] := $23;
- LNonce[2] := $45;
- LNonce[3] := $67;
- LNonce[4] := $89;
- LNonce[5] := $ab;
- LNonce[6] := $cd;
- LNonce[7] := $ef;
- SetLength(LCNonce,8);
- LCNonce[0] := $ff;
- LCNonce[1] := $ff;
- LCNonce[2] := $ff;
- LCNonce[3] := $00;
- LCNonce[4] := $11;
- LCNonce[5] := $22;
- LCNonce[6] := $33;
- LCNonce[7] := $44;
- SetLength(LTargetInfo,Length(TEST_TARGETINFO));
- CopyTIdByteArray(TEST_TARGETINFO,0,LTargetInfo,0,Length(TEST_TARGETINFO));
- if ToHex(SetupLMResponse(lmhash,'SecREt01',LNonce)) <> 'C337CD5CBD44FC9782A667AF6D427C6DE67C20C2D3E77C56' then
- begin
- DebugOutput(BytesToHex(LNonce));
- raise Exception.Create('LM Response test failed');
- end;
- if ToHex(CreateNTLMResponse(lmhash,'SecREt01',LNonce)) <> '25A98C1C31E81847466B29B2DF4680F39958FB8C213A9CC6' then
- begin
- raise Exception.Create('NTLM Response test failed');
- end;
- if ToHex(CreateModNTLMv1Response(lmhash,'user','SecREt01',LCNonce,LNonce,LMResp)) <> '10D550832D12B2CCB79D5AD1F4EED3DF82ACA4C3681DD455' then
- begin
- raise Exception.Create ('NTLM2 Session Response failed');
- end;
- if ToHex(LMResp) <> 'FFFFFF001122334400000000000000000000000000000000' then
- begin
- raise Exception.Create ('LM Response for NTLM2 reponse failed');
- end;
- if ToHex(SetupLMv2Response(lmhash,'user','DOMAIN','SecREt01',LCNonce,LNonce)) <> 'D6E6152EA25D03B7C6BA6629C2D6AAF0FFFFFF0011223344' then
- begin
- raise Exception.Create ( 'LMv2 Response failed');
- end;
- Ltst := ToHex(InternalCreateNTLMv2Response(lmhash,'user','DOMAIN','SecREt01',LTargetInfo,UnixTimeToFileTime(1055844000),LCNonce,LNonce ));
- if LTst <>
- 'CBABBCA713EB795D04C97ABC01EE4983'+
- '01010000000000000090D336B734C301'+
- 'FFFFFF00112233440000000002000C00' +
- '44004F004D00410049004E0001000C00' +
- '53004500520056004500520004001400' +
- '64006F006D00610069006E002E006300' +
- '6F006D00030022007300650072007600' +
- '650072002E0064006F006D0061006900' +
- '6E002E0063006F006D00000000000000' +
- '0000' then
- begin
- raise Exception.Create ('NTLMv2 Response failed' );
- end;
- end;
- function ConstArray(const AArray : array of byte) : TIdBytes;
- var
- i : Integer;
- begin
- SetLength(Result,0);
- for i := Low(AArray) to High(AArray) do begin
- AppendByte(Result,AArray[i]);
- end;
- end;
- {
- Microsoft tests
- User
- 0000000: 55 00 73 00 65 00 72 00 U.s.e.r.
- 0000000: 55 00 53 00 45 00 52 00 U.S.E.R.
- 0000000: 55 73 65 72 User
- UserDom
- 0000000: 44 00 6f 00 6d 00 61 00 69 00 6e 00 D.o.m.a.i.n
- Password
- 0000000: 50 00 61 00 73 00 73 00 77 00 6f 00 72 00 64 00 P.a.s.s.w.o.r.d.
- 0000000: 50 41 53 53 57 4f 52 44 00 00 00 00 00 00 PASSWORD......
- Server Name
- 00000000: 53 00 65 00 72 00 76 00 65 00 72 00 S.e.r.v.e.r.
- Workstation Name
- 0000000: 43 00 4f 00 4d 00 50 00 55 00 54 00 45 00 52 00 C.O.M.P.U.T.E.R.
- Random Session Key
- 0000000: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
- Time
- 0000000: 00 00 00 00 00 00 00 00 ........
- Client Challange
- 0000000: aa aa aa aa aa aa aa aa ........
- Server Challange
- 0000000: 01 23 45 67 89 ab cd ef .#Eg..═.
- 4.2.2 NTLM v1 Authentication
- # NTLMSSP_NEGOTIATE_KEY_EXCH
- # NTLMSSP_NEGOTIATE_56
- # NTLMSSP_NEGOTIATE_128
- # NTLMSSP_NEGOTIATE_VERSION
- # NTLMSSP_TARGET_TYPE_SERVER
- # NTLMSSP_NEGOTIATE_ALWAYS_SIGN
- # NTLM NTLMSSP_NEGOTIATE_NTLM
- # NTLMSSP_NEGOTIATE_SEAL
- # NTLMSSP_NEGOTIATE_SIGN
- # NTLM_NEGOTIATE_OEM
- # NTLMSSP_NEGOTIATE_UNICOD
- NTLMv1 data flags
- 33 82 02 e2
- }
- procedure DoMSTests;
- var
- LFlags : UInt32;
- LEncoding: IIdTextEncoding;
- begin
- LFlags := IdNTLMSSP_NEGOTIATE_KEY_EXCH or
- IdNTLMSSP_NEGOTIATE_56 or IdNTLMSSP_NEGOTIATE_128 or
- IdNTLMSSP_NEGOTIATE_VERSION or IdNTLMSSP_TARGET_TYPE_SERVER or
- IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN or IdNTLMSSP_NEGOTIATE_NTLM or
- IdNTLMSSP_NEGOTIATE_SEAL or IdNTLMSSP_NEGOTIATE_SIGN or
- IdNTLM_NEGOTIATE_OEM or IdNTLMSSP_NEGOTIATE_UNICODE;
- if ToHex(ToBytes(LFlags))<>'338202E2' then
- begin
- raise Exception.Create('MS Tests failed - NTLMv1 data flags');
- end;
- // if ToHex(NTOWFv1('Password') ) <> UpperCase('e52cac67419a9a224a3b108f3fa6cb6d') then
- LEncoding := IndyTextEncoding_ASCII;
- if ToHex(LMOWFv1(
- LEncoding.GetBytes(Uppercase( 'Password')),
- LEncoding.GetBytes(Uppercase( 'User')),
- LEncoding.GetBytes(Uppercase( 'Domain')))) <>
- Uppercase('e52cac67419a9a224a3b108f3fa6cb6d') then
- begin
- raise Exception.Create('MS Tests failed - LMOWFv1');
- end;
- end;
- procedure TestNTLM;
- begin
- // DoMSTests;
- DoDavePortTests;
- end;
- {$ENDIF}
- initialization
- SetLength(IdNTLM_SSP_SIG,8);
- IdNTLM_SSP_SIG[0] :=$4e; //N
- IdNTLM_SSP_SIG[1] :=$54; //T
- IdNTLM_SSP_SIG[2] :=$4c; //L
- IdNTLM_SSP_SIG[3] :=$4d; //M
- IdNTLM_SSP_SIG[4] :=$53; //S
- IdNTLM_SSP_SIG[5] :=$53; //S
- IdNTLM_SSP_SIG[6] :=$50; //P
- IdNTLM_SSP_SIG[7] :=$00; //#00
- UnixEpoch := EncodeDate(1970, 1, 1);
- end.
|