IdNTLMv2.pas 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749
  1. unit IdNTLMv2;
  2. interface
  3. {$i IdCompilerDefines.inc}
  4. uses
  5. IdGlobal,
  6. IdStruct
  7. {$IFNDEF DOTNET}, IdCTypes{$ENDIF}
  8. ;
  9. type
  10. ProtocolArray = array [ 1.. 8] of TIdAnsiChar;
  11. nonceArray = Array[ 1.. 8] of TIdAnsiChar;
  12. const
  13. //These are from:
  14. // http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
  15. // and the code is under a BSD license
  16. IdNTLMSSP_NEGOTIATE_UNICODE = $00000001; //A - NTLMSSP_NEGOTIATE_UNICODE
  17. IdNTLM_NEGOTIATE_OEM = $00000002; //B - NTLM_NEGOTIATE_OEM
  18. IdNTLMSSP_REQUEST_TARGET = $00000004; //C - NTLMSSP_REQUEST_TARGET
  19. IdNTLM_Unknown1 = $00000008; //r9 - should be zero
  20. IdNTLMSSP_NEGOTIATE_SIGN = $00000010; //D - NTLMSSP_NEGOTIATE_SIGN
  21. IdNTLMSSP_NEGOTIATE_SEAL = $00000020; //E - NTLMSSP_NEGOTIATE_SEAL
  22. IdNTLMSSP_NEGOTIATE_DATAGRAM = $00000040; //F - NTLMSSP_NEGOTIATE_DATAGRAM
  23. IdNTLMSSP_NEGOTIATE_LM_KEY = $00000080; //G - NTLMSSP_NEGOTIATE_LM_KEY
  24. //mentioned in http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
  25. //and http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
  26. //header. MS now says that is unused so it should be zero.
  27. IdNTLMSSP_NEGOTIATE_NETWARE = $00000100; //r8 - should be zero
  28. IdNTLMSSP_NEGOTIATE_NTLM = $00000200; //H - NTLMSSP_NEGOTIATE_NTLM
  29. IdNTLMSSP_NEGOTIATE_NT_ONLY = $00000400; //I - NTLMSSP_NEGOTIATE_NT_ONLY
  30. IdNTLMSSP_ANONYMOUS = $00000800; //J -
  31. IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = $00001000; //K - NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
  32. IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = $00002000; //L - NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
  33. //mentioned in http://svn.xmpp.ru/repos/tkabber/trunk/tkabber/jabberlib/ntlm.tcl
  34. //and http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
  35. //header. MS now says that is unused so it should be zero.
  36. IdNTLMSSP_NEGOTIATE_LOCAL_CALL = $00004000; //r6 - should be zero
  37. IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN = $00008000; //M - NTLMSSP_NEGOTIATE_ALWAYS_SIGN
  38. IdNTLMSSP_TARGET_TYPE_DOMAIN = $00010000; //N - NTLMSSP_TARGET_TYPE_DOMAIN
  39. IdNTLMSSP_TARGET_TYPE_SERVER = $00020000; //O - NTLMSSP_TARGET_TYPE_SERVER
  40. IdNTLMSSP_TARGET_TYPE_SHARE = $00040000; //P - NTLMSSP_TARGET_TYPE_SHARE
  41. IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = $00080000; //Q - NTLMSSP_NEGOTIATE_NTLM2
  42. //was NTLMSSP_REQUEST_INIT_RESPONSE 0x100000
  43. IdNTLMSSP_NEGOTIATE_IDENTIFY = $00100000; //R - NTLMSSP_NEGOTIATE_IDENTIFY
  44. IdNTLMSSP_REQUEST_ACCEPT_RESPONSE = $00200000; //r5 - should be zero
  45. //mentioned in http://doc.ddart.net/msdn/header/include/ntlmsp.h.html from an old ntlmsp.h
  46. //header. MS now says that is unused so it should be zero.
  47. IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY = $00400000; //S - NTLMSSP_REQUEST_NON_NT_SESSION_KEY
  48. IdNTLMSSP_NEGOTIATE_TARGET_INFO = $00800000; //T - NTLMSSP_NEGOTIATE_TARGET_INFO
  49. IdNTLM_Unknown4 = $01000000; //r4 - should be zero
  50. IdNTLMSSP_NEGOTIATE_VERSION = $02000000; //U - NTLMSSP_NEGOTIATE_VERSION
  51. // 400000
  52. IdNTLM_Unknown6 = $04000000; //r3 - should be zero
  53. IdNTLM_Unknown7 = $08000000; //r2 - should be zero
  54. IdNTLM_Unknown8 = $10000000; //r1 - should be zero
  55. IdNTLMSSP_NEGOTIATE_128 = $20000000; //V - NTLMSSP_NEGOTIATE_128
  56. IdNTLMSSP_NEGOTIATE_KEY_EXCH = $40000000; //W - NTLMSSP_NEGOTIATE_KEY_EXCH
  57. IdNTLMSSP_NEGOTIATE_56 = $80000000; //X - NTLMSSP_NEGOTIATE_56
  58. const
  59. //LC2 supports NTLMv2 only
  60. IdNTLM_TYPE1_FLAGS_LC2 = IdNTLMSSP_NEGOTIATE_UNICODE or
  61. IdNTLM_NEGOTIATE_OEM or
  62. IdNTLMSSP_REQUEST_TARGET or
  63. IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
  64. IdNTLM_TYPE1_FLAGS = IdNTLMSSP_NEGOTIATE_UNICODE or
  65. IdNTLM_NEGOTIATE_OEM or
  66. IdNTLMSSP_REQUEST_TARGET or
  67. IdNTLMSSP_NEGOTIATE_NTLM or
  68. // IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN or
  69. IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
  70. IdNTLM_TYPE1_MARKER : UInt32 = 1;
  71. IdNTLM_TYPE2_MARKER : UInt32 = 2;
  72. IdNTLM_TYPE3_MARKER : UInt32 = 3;
  73. IdNTLM_NTLMSSP_DES_KEY_LENGTH =7;
  74. IdNTLM_NTLMSSP_CHALLENGE_SIZE = 8;
  75. IdNTLM_LM_HASH_SIZE = 16;
  76. IdNTLM_LM_SESS_HASH_SIZE = 16;
  77. IdNTLM_LM_RESPONSE_SIZE = 24;
  78. IdNTLM_NTLMSSP_HASH_SIZE = 16;
  79. IdNTLM_NTLMSSP_RESPONSE_SIZE = 24;
  80. IdNTLM_NTLMSSP_V2_HASH_SIZE = 6;
  81. IdNTLM_NTLMSSP_V2_RESPONSE_SIZE = 16;
  82. IdNTLM_NONCE_LEN = 8;
  83. IdNTLM_TYPE2_TNAME_LEN_OFS = 12;
  84. IdNTLM_TYPE2_TNAME_OFFSET_OFS = 16;
  85. IdNTLM_TYPE2_FLAGS_OFS = 20;
  86. IdNTLM_TYPE2_NONCE_OFS = 24;
  87. IdNTLM_TYPE2_TINFO_LEN_OFS = 40;
  88. IdNTLM_TYPE2_TINFO_OFFSET_OFS = 44;
  89. IdNTLM_TYPE3_DOM_OFFSET = 64;
  90. //version info constants
  91. IdNTLM_WINDOWS_MAJOR_VERSION_5 = $05;
  92. IdNTLM_WINDOWS_MAJOR_VERSION_6 = $06;
  93. IdNTLM_WINDOWS_MINOR_VERSION_0 = $00;
  94. IdNTLM_WINDOWS_MINOR_VERSION_1 = $01;
  95. IdNTLM_WINDOWS_MINOR_VERSION_2 = $02;
  96. //original rel. build version of Vista
  97. //This isn't in the headers but I found easy enough.
  98. //It's provided because some NTLM servers might want ver info
  99. //from us. So we want to provide some dummy version and
  100. //Windows Vista is logical enough.
  101. IdNTLM_WINDOWS_BUILD_ORIG_VISTA = 6000;
  102. var
  103. IdNTLM_SSP_SIG : TIdBytes;
  104. UnixEpoch : TDateTime;
  105. {$DEFINE TESTSUITE}
  106. {$IFDEF TESTSUITE}
  107. procedure TestNTLM;
  108. {$ENDIF}
  109. function BuildType1Msg(const ADomain : String = ''; const AHost : String = ''; const ALMCompatibility : UInt32 = 0) : TIdBytes;
  110. procedure ReadType2Msg(const AMsg : TIdBytes; var VFlags : UInt32; var VTargetName : TIdBytes; var VTargetInfo : TIdBytes; var VNonce : TIdBytes );
  111. function BuildType3Msg(const ADomain, AHost, AUsername, APassword : String;
  112. const AFlags : UInt32; const AServerNonce : TIdBytes;
  113. const ATargetName, ATargetInfo : TIdBytes;
  114. const ALMCompatibility : UInt32 = 0) : TIdBytes;
  115. {
  116. function BuildType1Message( ADomain, AHost: String; const AEncodeMsg : Boolean = True): String;
  117. procedure ReadType2Message(const AMsg : String; var VNonce : nonceArray; var Flags : UInt32);
  118. function BuildType3Message( ADomain, AHost, AUsername: TIdUnicodeString; APassword : String; AServerNonce : nonceArray): String;
  119. }
  120. function NTLMFunctionsLoaded : Boolean;
  121. procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
  122. function DumpFlags(const ABytes : TIdBytes): String; overload;
  123. function DumpFlags(const AFlags : UInt32): String; overload;
  124. function LoadRC4 : Boolean;
  125. function RC4FunctionsLoaded : Boolean;
  126. implementation
  127. uses
  128. SysUtils,
  129. {$IFDEF USE_VCL_POSIX}
  130. PosixTime,
  131. {$ENDIF}
  132. {$IFDEF DOTNET}
  133. Classes,
  134. System.Runtime.InteropServices,
  135. System.Runtime.InteropServices.ComTypes,
  136. System.Security.Cryptography,
  137. System.Text,
  138. {$ELSE}
  139. {$IFDEF FPC}
  140. DynLibs, // better add DynLibs only for fpc
  141. {$ENDIF}
  142. {$IFDEF WINDOWS}
  143. //Windows should really not be included but this protocol does use
  144. //some windows internals and is Windows-based.
  145. Windows,
  146. {$ENDIF}
  147. {$ENDIF}
  148. IdFIPS,
  149. IdGlobalProtocols,
  150. IdHash,
  151. IdHMACMD5,
  152. IdHashMessageDigest,
  153. IdCoderMIME
  154. {$IFNDEF DOTNET}, IdSSLOpenSSLHeaders{$ENDIF} // TODO: remove dependency on this!
  155. ;
  156. const
  157. {$IFDEF DOTNET}
  158. MAGIC : array [ 0.. 7] of byte = ( $4b, $47, $53, $21, $40, $23, $24, $25);
  159. {$ELSE}
  160. Magic: des_cblock = ( $4B, $47, $53, $21, $40, $23, $24, $25 );
  161. Magic_const : array [0..7] of byte = ( $4b, $47, $53, $21, $40, $23, $24, $25 );
  162. {$ENDIF}
  163. TYPE1_MARKER = 1;
  164. TYPE2_MARGER = 2;
  165. TYPE3_MARKER = 3;
  166. //const
  167. // NUL_USER_SESSION_KEY : TIdBytes[0..15] = ($00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00);
  168. {$IFNDEF DOTNET}
  169. type
  170. Pdes_key_schedule = ^des_key_schedule;
  171. {$IFNDEF WINDOWS}
  172. FILETIME = record
  173. dwLowDateTime : UInt32;
  174. dwHighDateTime : UInt32;
  175. end;
  176. {$ENDIF}
  177. {$ENDIF}
  178. {$IFNDEF DOTNET}
  179. //const char *RC4_options(void);
  180. var
  181. GRC4_Options : function () : PIdAnsiChar; cdecl = nil;
  182. //void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
  183. GRC4_set_key : procedure(key : PRC4_KEY; len : TIdC_INT; data : PIdAnsiChar); cdecl = nil;
  184. //void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata,
  185. // unsigned char *outdata);
  186. GRC4 : procedure (key : PRC4_KEY; len : TIdC_ULONG; indata, outdata : PIdAnsiChar) ; cdecl = nil;
  187. {$ENDIF}
  188. function NulUserSessionKey : TIdBytes;
  189. begin
  190. SetLength(Result,16);
  191. FillChar(Result,16,0);
  192. end;
  193. //misc routines that might be helpful in some other places
  194. //===================
  195. {$IFDEF DOTNET}
  196. function Int64ToFileTime(const AInt64 : Int64) : System.Runtime.InteropServices.ComTypes.FILETIME;
  197. var
  198. LBytes : TIdBytes;
  199. begin
  200. LBytes := BitConverter.GetBytes(AInt64);
  201. Result.dwLowDateTime := BitConverter.ToInt32(Lbytes, 0);
  202. Result.dwHighDateTime := BitConverter.ToInt32(Lbytes, 4);
  203. end;
  204. function UnixTimeToFileTime(const AUnixTime : UInt32) : System.Runtime.InteropServices.ComTypes.FILETIME;
  205. {$ELSE}
  206. {
  207. We do things this way because in Win64, FILETIME may not be a simple typecast
  208. of Int64. It might be a two dword record that's aligned on an 8-byte
  209. boundery.
  210. }
  211. {$UNDEF USE_FILETIME_TYPECAST}
  212. {$IFDEF WINCE}
  213. {$DEFINE USE_FILETIME_TYPECAST}
  214. {$ENDIF}
  215. {$IFDEF WIN32}
  216. {$DEFINE USE_FILETIME_TYPECAST}
  217. {$ENDIF}
  218. function UnixTimeToFileTime(const AUnixTime : UInt32) : FILETIME;
  219. var
  220. i : Int64;
  221. {$ENDIF}
  222. begin
  223. {$IFDEF DOTNET}
  224. Result := Int64ToFileTime((AUnixTime + 11644473600) * 10000000);
  225. {$ELSE}
  226. i := (AUnixTime + 11644473600) * 10000000;
  227. {$IFDEF USE_FILETIME_TYPECAST}
  228. Result := FILETIME(i);
  229. {$ELSE}
  230. Result.dwLowDateTime := i and $FFFFFFFF;
  231. Result.dwHighDateTime := i shr 32;
  232. {$ENDIF}
  233. {$ENDIF}
  234. end;
  235. function NowAsFileTime : FILETIME;
  236. {$IFDEF DOTNET}
  237. {$IFDEF USE_INLINE} inline; {$ENDIF}
  238. {$ENDIF}
  239. {$IFDEF UNIX}
  240. {$IFNDEF USE_VCL_POSIX}
  241. var
  242. TheTms: tms;
  243. {$ENDIF}
  244. {$ENDIF}
  245. begin
  246. {$IFDEF WINDOWS}
  247. {$IFDEF WINCE}
  248. // TODO
  249. {$ELSE}
  250. Windows.GetSystemTimeAsFileTime(Result);
  251. {$ENDIF}
  252. {$ENDIF}
  253. {$IFDEF UNIX}
  254. {$IFDEF USE_VCL_BASEUNIX}
  255. Result := UnixTimeToFileTime( fptimes (TheTms));
  256. {$ENDIF}
  257. //Is the following correct?
  258. {$IFDEF KYLIXCOMPAT}
  259. Result := UnixTimeToFileTime(Times(TheTms));
  260. {$ENDIF}
  261. {$IFDEF USE_VCL_POSIX}
  262. Result := UnixTimeToFileTime(PosixTime.time(nil));
  263. {$ENDIF}
  264. {$ENDIF}
  265. {$IFDEF DOTNET}
  266. Result := Int64ToFileTime(DateTime.Now.ToFileTimeUtc);
  267. // Result := System.DateTime.Now.Ticks;
  268. {$ENDIF}
  269. end;
  270. function ConcateBytes(const A1, A2 : TIdBytes) : TIdBytes;
  271. begin
  272. Result := A1;
  273. IdGlobal.AppendBytes(Result,A2);
  274. end;
  275. procedure CharArrayToBytes(const AArray : Array of char; var VBytes : TIdBytes; const AIndex : Integer=0);
  276. var
  277. i, ll, lh : Integer;
  278. begin
  279. ll := Low( AArray);
  280. lh := High( AArray);
  281. for i := ll to lh do begin
  282. VBytes[i] := Ord( AArray[ i]);
  283. end;
  284. end;
  285. procedure BytesToCharArray(const ABytes : TIdBytes; var VArray : Array of char; const AIndex : Integer=0);
  286. var
  287. i, ll, lh : Integer;
  288. begin
  289. ll := Low( VArray);
  290. lh := High( Varray);
  291. for i := ll to lh do begin
  292. VArray[ i] := Char( Abytes[ (i - ll) + AIndex]);
  293. end;
  294. end;
  295. procedure BytesToByteArray(const ABytes : TIdBytes; var VArray : Array of byte; const AIndex : Integer=0);
  296. var
  297. i, ll, lh : Integer;
  298. begin
  299. ll := Low(VArray);
  300. lh := High(Varray);
  301. for i := ll to lh do begin
  302. VArray[i] := Abytes[ (i - ll) + AIndex];
  303. end;
  304. end;
  305. procedure ByteArrayToBytes(const VArray : array of byte; const ABytes : TIdBytes; const AIndex : Integer=0);
  306. var
  307. i, ll, lh : Integer;
  308. begin
  309. ll := Low( VArray);
  310. lh := High( Varray);
  311. for i := ll to lh do begin
  312. Abytes[ (i - ll) + AIndex] := VArray[i];
  313. end;
  314. end;
  315. //---------------------------
  316. //end misc routines
  317. function DumpFlags(const ABytes : TIdBytes): String;
  318. {$IFDEF USE_INLINE}inline;{$ENDIF}
  319. begin
  320. Result := DumpFlags( LittleEndianToHost(BytesToUInt32(ABytes)));
  321. end;
  322. function DumpFlags(const AFlags : UInt32): String;
  323. {$IFDEF USE_INLINE}inline;{$ENDIF}
  324. begin
  325. Result := IntToHex(AFlags,8)+' -';
  326. if AFlags and IdNTLMSSP_NEGOTIATE_UNICODE <> 0 then
  327. begin
  328. Result := Result + ' IdNTLMSSP_NEGOTIATE_UNICODE';
  329. end;
  330. if AFlags and IdNTLM_NEGOTIATE_OEM <> 0 then begin
  331. Result := Result + ' IdNTLM_NEGOTIATE_OEM';
  332. end;
  333. if AFlags and IdNTLMSSP_REQUEST_TARGET <> 0 then begin
  334. Result := Result + ' IdNTLMSSP_REQUEST_TARGET';
  335. end;
  336. if AFlags and IdNTLM_Unknown1 <> 0 then begin
  337. Result := Result + ' IdNTLM_Unknown1';
  338. end;
  339. if AFlags and IdNTLMSSP_NEGOTIATE_SIGN <> 0 then begin
  340. Result := Result + ' IdNTLMSSP_NEGOTIATE_SIGN';
  341. end;
  342. if AFlags and IdNTLMSSP_NEGOTIATE_SEAL <> 0 then begin
  343. Result := Result + ' IdNTLMSSP_NEGOTIATE_SEAL';
  344. end;
  345. if AFlags and IdNTLMSSP_NEGOTIATE_DATAGRAM <> 0 then begin
  346. Result := Result + ' IdNTLMSSP_NEGOTIATE_DATAGRAM';
  347. end;
  348. if AFlags and IdNTLMSSP_NEGOTIATE_LM_KEY <> 0 then begin
  349. Result := Result + ' IdNTLMSSP_NEGOTIATE_LM_KEY';
  350. end;
  351. if AFlags and IdNTLMSSP_NEGOTIATE_NETWARE <> 0 then begin
  352. Result := Result + ' IdNTLMSSP_NEGOTIATE_NETWARE';
  353. end;
  354. if AFlags and IdNTLMSSP_NEGOTIATE_NTLM <> 0 then begin
  355. Result := Result + ' IdNTLMSSP_NEGOTIATE_NTLM';
  356. end;
  357. if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then begin
  358. Result := Result + ' IdNTLMSSP_NEGOTIATE_NT_ONLY';
  359. end;
  360. if AFlags and IdNTLMSSP_ANONYMOUS <> 0 then begin
  361. Result := Result + ' IdNTLMSSP_ANONYMOUS';
  362. end;
  363. if AFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED <> 0 then begin
  364. Result := Result + ' IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED';
  365. end;
  366. if AFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED <> 0 then begin
  367. Result := Result + ' IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED';
  368. end;
  369. if AFlags and IdNTLMSSP_NEGOTIATE_LOCAL_CALL <> 0 then begin
  370. Result := Result + ' IdNTLMSSP_NEGOTIATE_LOCAL_CALL';
  371. end;
  372. if AFlags and IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN <> 0 then begin
  373. Result := Result + ' IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN';
  374. end;
  375. if AFlags and IdNTLMSSP_TARGET_TYPE_DOMAIN <> 0 then begin
  376. Result := Result + ' IdNTLMSSP_TARGET_TYPE_DOMAIN';
  377. end;
  378. if AFlags and IdNTLMSSP_TARGET_TYPE_SERVER <> 0 then begin
  379. Result := Result + ' IdNTLMSSP_TARGET_TYPE_SERVER';
  380. end;
  381. if AFlags and IdNTLMSSP_TARGET_TYPE_SHARE <> 0 then begin
  382. Result := Result + ' IdNTLMSSP_TARGET_TYPE_SHARE';
  383. end;
  384. if AFlags and IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY <> 0 then begin
  385. Result := Result + ' IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY';
  386. end;
  387. if AFlags and IdNTLMSSP_NEGOTIATE_IDENTIFY <> 0 then begin
  388. Result := Result + ' IdNTLMSSP_NEGOTIATE_IDENTIFY';
  389. end;
  390. if AFlags and IdNTLMSSP_REQUEST_ACCEPT_RESPONSE <> 0 then begin
  391. Result := Result + ' IdNTLMSSP_REQUEST_ACCEPT_RESPONSE';
  392. end;
  393. if AFlags and IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY <> 0 then begin
  394. Result := Result + ' IdIdNTLMSSP_REQUEST_NON_NT_SESSION_KEY';
  395. end;
  396. if AFlags and IdNTLMSSP_NEGOTIATE_TARGET_INFO <> 0 then begin
  397. Result := Result + ' IdNTLMSSP_NEGOTIATE_TARGET_INFO';
  398. end;
  399. if AFlags and IdNTLM_Unknown4 <> 0 then begin
  400. Result := Result + ' IdNTLM_Unknown4';
  401. end;
  402. if AFlags and IdNTLMSSP_NEGOTIATE_VERSION <> 0 then begin
  403. Result := Result + ' IdNTLMSSP_NEGOTIATE_VERSION';
  404. end;
  405. if AFlags and IdNTLM_Unknown8 <> 0 then begin
  406. Result := Result + ' IdNTLM_Unknown8';
  407. end;
  408. if AFlags and IdNTLM_Unknown7 <> 0 then begin
  409. Result := Result + ' IdNTLM_Unknown7';
  410. end;
  411. if AFlags and IdNTLM_Unknown8 <> 0 then begin
  412. Result := Result + ' IdNTLM_Unknown8';
  413. end;
  414. if AFlags and IdNTLMSSP_NEGOTIATE_128 <> 0 then begin
  415. Result := Result + ' IdNTLMSSP_NEGOTIATE_128';
  416. end;
  417. if AFlags and IdNTLMSSP_NEGOTIATE_KEY_EXCH <> 0 then begin
  418. Result := Result + ' IdNTLMSSP_NEGOTIATE_KEY_EXCH';
  419. end;
  420. if AFlags and IdNTLMSSP_NEGOTIATE_56 <> 0 then begin
  421. Result := Result + ' IdNTLMSSP_NEGOTIATE_56';
  422. end;
  423. end;
  424. {$IFDEF DOTNET}
  425. const
  426. DES_ODD_PARITY : array[ 0.. 255] of byte =
  427. ( 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
  428. 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
  429. 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
  430. 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
  431. 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
  432. 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
  433. 97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110,
  434. 112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127,
  435. 128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143,
  436. 145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158,
  437. 161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174,
  438. 176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191,
  439. 193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206,
  440. 208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223,
  441. 224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239,
  442. 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254);
  443. {
  444. IMPORTANT!!!
  445. In the NET framework, the DES API will not accept a weak key. Unfortunately,
  446. in NTLM's LM password, if a password is less than 8 charactors, the second key
  447. is weak. This is one flaw in that protocol.
  448. To workaround this, we use a precalculated key of zeros with the parity bit set
  449. and encrypt the MAGIC value with it. The Mono framework also does this.
  450. }
  451. const
  452. MAGIC_NUL_KEY : array [ 0.. 7] of byte = ($AA,$D3,$B4,$35,$B5,$14,$04,$EE);
  453. {barrowed from OpenSSL source-code - crypto/des/set_key.c 0.9.8g}
  454. {
  455. I barrowed it since it seems to work better than the NTLM sample code and because
  456. Microsoft.NET does not have this functionality when it really should have it.
  457. }
  458. procedure SetDesKeyOddParity(var VKey : TIdBytes);
  459. {$IFDEF USE_INLINE} inline; {$ENDIF}
  460. var
  461. i, l : Integer;
  462. begin
  463. l := Length( VKey);
  464. for i := 0 to l - 1 do begin
  465. VKey[ i] := DES_ODD_PARITY[ VKey[ i]];
  466. end;
  467. end;
  468. {$ENDIF}
  469. procedure GetDomain(const AUserName : String; var VUserName, VDomain : String);
  470. {$IFDEF USE_INLINE} inline; {$ENDIF}
  471. var
  472. i : Integer;
  473. begin
  474. {
  475. Can be like this:
  476. DOMAIN\user
  477. domain.com\user
  478. user@DOMAIN
  479. }
  480. i := IndyPos('\', AUsername);
  481. if i > 0 then begin //was -1
  482. VDomain := Copy( AUsername, 1, i - 1);
  483. VUserName := Copy( AUsername, i + 1, Length( AUserName));
  484. end else begin
  485. i := IndyPos('@',AUsername);
  486. if i > 0 then //was -1
  487. begin
  488. VUsername := Copy( AUsername, 1, i - 1);
  489. VDomain := Copy( AUsername, i + 1, Length( AUserName));
  490. end
  491. else
  492. begin
  493. VDomain := ''; {do not localize}
  494. VUserName := AUserName;
  495. end;
  496. end;
  497. end;
  498. {$IFDEF DOTNET}
  499. function NTLMFunctionsLoaded : Boolean;
  500. {$IFDEF USE_INLINE} inline; {$ENDIF}
  501. begin
  502. Result := True;
  503. end;
  504. {$ELSE}
  505. function NTLMFunctionsLoaded : Boolean;
  506. begin
  507. Result := LoadNTLMLibrary;
  508. if Result then begin
  509. Result := IsNTLMFuncsAvail;
  510. end;
  511. end;
  512. function LoadRC4 : Boolean;
  513. var
  514. h : Integer;
  515. begin
  516. Result := LoadNTLMLibrary;
  517. if Result then begin
  518. // TODO: move these into IndyTLSOpenSSL package and update IdFIPS unit...
  519. h := IdSSLOpenSSLHeaders.GetCryptLibHandle;
  520. GRC4_Options := LoadLibFunction(h,'RC4_options');
  521. GRC4_set_key := LoadLibFunction(h,'RC4_set_key');
  522. GRC4 := LoadLibFunction(h,'RC4');
  523. end;
  524. Result := RC4FunctionsLoaded;
  525. end;
  526. function RC4FunctionsLoaded : Boolean;
  527. begin
  528. // TODO: move these into IndyTLSOpenSSL package and update IdFIPS unit...
  529. // Result := IsNTLMv2FuncsAvail;
  530. Result := Assigned(GRC4_Options) and
  531. Assigned(GRC4_set_key) and
  532. Assigned(GRC4);
  533. end;
  534. {$ENDIF}
  535. //* create NT hashed password */
  536. function NTOWFv1(const APassword : String): TIdBytes;
  537. {$IFDEF USE_INLINE} inline; {$ENDIF}
  538. var
  539. LHash: TIdHashMessageDigest4;
  540. begin
  541. CheckMD4Permitted;
  542. LHash := TIdHashMessageDigest4.Create;
  543. {$IFNDEF USE_OBJECT_ARC}
  544. try
  545. {$ENDIF}
  546. Result := LHash.HashString(APassword, IndyTextEncoding_UTF16LE);
  547. {$IFNDEF USE_OBJECT_ARC}
  548. finally
  549. LHash.Free;
  550. end;
  551. {$ENDIF}
  552. end;
  553. {$IFNDEF DOTNET}
  554. {/*
  555. * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
  556. * The key schedule ks is also set.
  557. */}
  558. procedure setup_des_key(key_56: des_cblock; Var ks: des_key_schedule);
  559. {$IFDEF USE_INLINE}inline;{$ENDIF}
  560. var
  561. key: des_cblock;
  562. begin
  563. key[0] := key_56[0];
  564. key[1] := ((key_56[0] SHL 7) and $FF) or (key_56[1] SHR 1);
  565. key[2] := ((key_56[1] SHL 6) and $FF) or (key_56[2] SHR 2);
  566. key[3] := ((key_56[2] SHL 5) and $FF) or (key_56[3] SHR 3);
  567. key[4] := ((key_56[3] SHL 4) and $FF) or (key_56[4] SHR 4);
  568. key[5] := ((key_56[4] SHL 3) and $FF) or (key_56[5] SHR 5);
  569. key[6] := ((key_56[5] SHL 2) and $FF) or (key_56[6] SHR 6);
  570. key[7] := (key_56[6] SHL 1) and $FF;
  571. DES_set_odd_parity(@key);
  572. DES_set_key(@key, ks);
  573. end;
  574. //Returns 8 bytes in length
  575. procedure _DES(var Res : TIdBytes; const Akey, AData : array of byte; const AKeyIdx, ADataIdx, AResIdx : Integer);
  576. var
  577. Lks: des_key_schedule;
  578. begin
  579. setup_des_key(pdes_cblock(@Akey[AKeyIdx])^, Lks);
  580. DES_ecb_encrypt(@AData[ADataIdx], Pconst_DES_cblock(@Res[AResIdx]), Lks, DES_ENCRYPT);
  581. end;
  582. function LMOWFv1(const Passwd, User, UserDom : TIdBytes) : TIdBytes;
  583. // ConcatenationOf( DES( UpperCase( Passwd)[0..6],"KGS!@#$%"),
  584. // DES( UpperCase( Passwd)[7..13],"KGS!@#$%"))
  585. var
  586. LBuf : TIdBytes;
  587. begin
  588. SetLength(Result,16);
  589. SetLength(LBuf,14);
  590. FillBytes( LBuf, 14, 0);
  591. CopyTIdBytes(Passwd,0,LBuf, 0,14);
  592. _DES(Result,LBuf, Magic_const,0,0,0);
  593. _DES(Result,LBuf, Magic_const,7,0,8);
  594. end;
  595. {/*
  596. * takes a 21 byte array and treats it as 3 56-bit DES keys. The
  597. * 8 byte plaintext is encrypted with each key and the resulting 24
  598. * bytes are stored in the results array.
  599. */}
  600. procedure DESL(const Akeys: TIdBytes; const AServerNonce: TIdBytes; out results: TIdBytes);
  601. //procedure DESL(keys: TIdBytes; AServerNonce: TIdBytes; results: TIdBytes);
  602. //procedure DESL(keys: TIdBytes; AServerNonce: TIdBytes; results: Pdes_key_schedule);
  603. var
  604. ks: des_key_schedule;
  605. begin
  606. SetLength(Results,24);
  607. setup_des_key(PDES_cblock(@Akeys[0])^, ks);
  608. DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(results), ks, DES_ENCRYPT);
  609. setup_des_key(PDES_cblock(Integer(Akeys) + 7)^, ks);
  610. DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(PtrUInt(results) + 8), ks, DES_ENCRYPT);
  611. setup_des_key(PDES_cblock(Integer(Akeys) + 14)^, ks);
  612. DES_ecb_encrypt(@AServerNonce[0], Pconst_DES_cblock(PtrUInt(results) + 16), ks, DES_ENCRYPT);
  613. end;
  614. //* setup LanManager password */
  615. function SetupLMResponse(var vlmHash : TIdBytes; const APassword : String; AServerNonce : TIdBytes): TIdBytes;
  616. var
  617. lm_hpw : TIdBytes;
  618. lm_pw : TIdBytes;
  619. ks: des_key_schedule;
  620. begin
  621. SetLength( lm_hpw,21);
  622. FillBytes( lm_hpw, 14, 0);
  623. SetLength( lm_pw, 21);
  624. FillBytes( lm_pw, 14, 0);
  625. SetLength( vlmHash, 16);
  626. CopyTIdString( UpperCase( APassword), lm_pw, 0, 14);
  627. //* create LanManager hashed password */
  628. setup_des_key(pdes_cblock(@lm_pw[0])^, ks);
  629. DES_ecb_encrypt(@magic, pconst_des_cblock(@lm_hpw[0]), ks, DES_ENCRYPT);
  630. setup_des_key(pdes_cblock(@lm_pw[7])^, ks);
  631. DES_ecb_encrypt(@magic, pconst_des_cblock(@lm_hpw[8]), ks, DES_ENCRYPT);
  632. CopyTIdBytes(lm_pw,0,vlmHash,0,16);
  633. // FillChar(lm_hpw[17], 5, 0);
  634. SetLength(Result,24);
  635. DESL(lm_hpw, AServerNonce, Result);
  636. // DESL(PDes_cblock(@lm_hpw[0]), AServerNonce, Pdes_key_schedule(@Result[0]));
  637. //
  638. end;
  639. //* create NT hashed password */
  640. function CreateNTLMResponse(var vntlmhash : TIdBytes; const APassword : String; const nonce : TIdBytes): TIdBytes;
  641. var
  642. nt_pw : TIdBytes;
  643. nt_hpw : TIdBytes; //array [1..21] of Char;
  644. begin
  645. nt_pw := NTOWFv1(APassword);
  646. SetLength( nt_hpw, 21);
  647. FillChar( nt_hpw[ 17], 5, 0);
  648. CopyTIdBytes( nt_pw, 0, nt_hpw, 0, 16);
  649. // done in DESL
  650. SetLength( Result, 24);
  651. // DESL(pdes_cblock(@nt_hpw[0]), nonce, Pdes_key_schedule(@Result[0]));
  652. DESL(nt_hpw, nonce, Result);
  653. end;
  654. {
  655. function CreateNTLMResponse(const APassword : String; const nonce : TIdBytes): TIdBytes;
  656. var
  657. nt_pw : TIdBytes;
  658. nt_hpw : array [ 1.. 21] of AnsiChar;
  659. LHash: TIdHashMessageDigest4;
  660. begin
  661. nt_pw := NTOWFv1(APassword);
  662. SetLength(Result,24);
  663. Move( nt_pw[ 0], nt_hpw[ 1], 16);
  664. FillChar( nt_hpw[ 17], 5, 0);
  665. DESL(pdes_cblock( @nt_hpw[1]), nonce, Pdes_key_schedule( @Result[ 0]));
  666. end;
  667. }
  668. {$ELSE}
  669. procedure setup_des_key(const Akey_56: TIdBytes; out Key : TIdBytes; const AIndex : Integer = 0);
  670. {$IFDEF USE_INLINE}inline;{$ENDIF}
  671. begin
  672. SetLength( key, 8);
  673. key[0] := Akey_56[ AIndex];
  674. key[1] := (( Akey_56[ AIndex] SHL 7) and $FF) or (Akey_56[ AIndex + 1] SHR 1);
  675. key[2] := (( Akey_56[ AIndex + 1] SHL 6) and $FF) or (Akey_56[ AIndex + 2] SHR 2);
  676. key[3] := (( Akey_56[ AIndex + 2] SHL 5) and $FF) or (Akey_56[ AIndex + 3] SHR 3);
  677. key[4] := (( Akey_56[ AIndex + 3] SHL 4) and $FF) or (Akey_56[ AIndex + 4] SHR 4);
  678. key[5] := (( Akey_56[ AIndex + 4] SHL 3) and $FF) or (Akey_56[ AIndex + 5] SHR 5);
  679. key[6] := (( Akey_56[ AIndex + 5] SHL 2) and $FF) or (Akey_56[ AIndex + 6] SHR 6);
  680. key[7] := ( AKey_56[ AIndex + 6] SHL 1) and $FF;
  681. SetDesKeyOddParity( Key);
  682. end;
  683. procedure DESL(const Akeys: TIdBytes; const AServerNonce: TIdBytes; out results: TIdBytes);
  684. var
  685. LKey : TIdBytes;
  686. LDes : System.Security.Cryptography.DES;
  687. LEnc : ICryptoTransform;
  688. begin
  689. SetLength( Results, 24);
  690. SetLength( LKey, 8);
  691. LDes := DESCryptoServiceProvider.Create;
  692. LDes.Mode := CipherMode.ECB;
  693. LDes.Padding := PaddingMode.None;
  694. setup_des_key( AKeys, LKey, 0);
  695. LDes.Key := LKey;
  696. LEnc := LDes.CreateEncryptor;
  697. LEnc.TransformBlock( AServerNonce, 0, 8, Results, 0);
  698. setup_des_key( AKeys, LKey, 7);
  699. LDes.Key := LKey;
  700. LEnc := LDes.CreateEncryptor;
  701. LEnc.TransformBlock( AServerNonce, 0, 8, Results, 8);
  702. setup_des_key(AKeys,LKey,14);
  703. LDes.Key := LKey;
  704. LEnc := LDes.CreateEncryptor;
  705. LEnc.TransformBlock( AServerNonce, 0, 8, Results, 16);
  706. end;
  707. function SetupLMResponse(const APassword : String; AServerNonce : TIdBytes): TIdBytes;
  708. var
  709. lm_hpw : TIdBytes; //array[1..21] of Char;
  710. lm_pw : TIdBytes; //array[1..21] of Char;
  711. LDes : System.Security.Cryptography.DES;
  712. LEnc : ICryptoTransform;
  713. LKey : TIdBytes;
  714. begin
  715. SetLength( lm_hpw,21);
  716. FillBytes( lm_hpw, 14, 0);
  717. SetLength( lm_pw, 21);
  718. FillBytes( lm_pw, 14, 0);
  719. CopyTIdString( UpperCase( APassword), lm_pw, 0, 14);
  720. LDes := DESCryptoServiceProvider.Create;
  721. LDes.Mode := CipherMode.ECB;
  722. LDes.Padding := PaddingMode.None;
  723. setup_des_key( lm_pw, LKey, 0);
  724. LDes.BlockSize := 64;
  725. LDes.Key := LKey;
  726. LEnc := LDes.CreateEncryptor;
  727. LEnc.TransformBlock( MAGIC, 0, 8, lm_hpw, 0);
  728. setup_des_key( lm_pw, LKey,7);
  729. if Length( APassword) > 7 then begin
  730. LDes.Key := LKey;
  731. LEnc := LDes.CreateEncryptor;
  732. LEnc.TransformBlock( MAGIC, 0, 8, lm_hpw, 8);
  733. end else begin
  734. CopyTIdBytes( MAGIC_NUL_KEY, 0, lm_hpw, 8, 8);
  735. end;
  736. DESL( lm_hpw, nonce, Result);
  737. end;
  738. function CreateNTLMResponse(const APassword : String; const nonce : TIdBytes): TIdBytes;
  739. var
  740. nt_pw : TIdBytes;
  741. nt_hpw : TIdBytes; //array [1..21] of Char;
  742. nt_hpw128 : TIdBytes;
  743. begin
  744. CheckMD4Permitted;
  745. nt_pw := System.Text.Encoding.Unicode.GetBytes( APassword);
  746. with TIdHashMessageDigest4.Create do try
  747. nt_hpw128 := HashString( nt_pw);
  748. finally
  749. Free;
  750. end;
  751. SetLength( nt_hpw, 21);
  752. FillBytes( nt_hpw, 21, 0);
  753. CopyTIdBytes( nt_hpw128, 0, nt_hpw, 0, 16);
  754. // done in DESL
  755. //SetLength( nt_resp, 24);
  756. DESL( nt_hpw,nonce, Result);
  757. end;
  758. {$ENDIF}
  759. procedure AddUInt16(var VBytes: TIdBytes; const AWord : UInt16);
  760. {$IFDEF USE_INLINE}inline;{$ENDIF}
  761. var
  762. LBytes : TIdBytes;
  763. begin
  764. SetLength(LBytes,SizeOf(AWord));
  765. CopyTIdUInt16(HostToLittleEndian(AWord),LBytes,0);
  766. AppendBytes( VBytes,LBytes);
  767. end;
  768. procedure AddUInt32(var VBytes: TIdBytes; const ALongWord : UInt32);
  769. {$IFDEF USE_INLINE}inline;{$ENDIF}
  770. var
  771. LBytes : TIdBytes;
  772. begin
  773. SetLength(LBytes,SizeOf(ALongWord));
  774. CopyTIdUInt32(HostToLittleEndian(ALongWord),LBytes,0);
  775. AppendBytes( VBytes,LBytes);
  776. end;
  777. procedure AddInt64(var VBytes: TIdBytes; const AInt64 : Int64);
  778. var
  779. LBytes : TIdBytes;
  780. begin
  781. SetLength(LBytes,SizeOf(AInt64));
  782. {$IFDEF ENDIAN_LITTLE}
  783. IdGlobal.CopyTIdInt64(AInt64,LBytes,0);
  784. {$ELSE}
  785. //done this way since we need this in little endian byte-order
  786. CopyTIdUInt32(HostToLittleEndian(Lo( AInt64)));
  787. CopyTIdUInt32(HostToLittleEndian(Hi( AInt64)));
  788. {$ENDIF}
  789. AppendBytes( VBytes,LBytes);
  790. end;
  791. {
  792. IMPORTANT!!! I think the time feilds in the NTLM blob are really FILETIME
  793. records.
  794. MSDN says that a Contains a 64-bit value representing the number of
  795. 100-nanosecond intervals since January 1, 1601 (UTC).
  796. http://davenport.sourceforge.net/ntlm.html says that the time feild is
  797. Little-endian, 64-bit signed value representing the number of tenths of a
  798. microsecond since January 1, 1601.
  799. In other words, they are the same. We use FILETIME for the API so that
  800. we can easily obtain a the timestamp for the blob in Microsoft.NET as well as
  801. Delphi (the work on proper format is already done for us.
  802. }
  803. const
  804. NTLMv2_BLOB_Sig : array [0..3] of byte = ($01,$01,$00,$00);
  805. NTLMv2_BLOB_Res : array [0..3] of byte = ($00,$00,$00,$00);
  806. function IndyByteArrayLength(const ABuffer: array of byte; const ALength: Integer = -1; const AIndex: Integer = 0): Integer;
  807. var
  808. LAvailable: Integer;
  809. begin
  810. Assert(AIndex >= 0);
  811. LAvailable := IndyMax(Length(ABuffer)-AIndex, 0);
  812. if ALength < 0 then begin
  813. Result := LAvailable;
  814. end else begin
  815. Result := IndyMin(LAvailable, ALength);
  816. end;
  817. end;
  818. procedure AddByteArray(var VBytes : TIdBytes; const AToAdd : array of byte; const AIndex: Integer = 0);
  819. var
  820. LOldLen, LAddLen : Integer;
  821. begin
  822. LAddLen := IndyByteArrayLength(AToAdd, -1, AIndex);
  823. if LAddLen > 0 then begin
  824. LOldLen := Length(VBytes);
  825. SetLength(VBytes, LOldLen + LAddLen);
  826. CopyTIdByteArray(AToAdd, AIndex, VBytes, LOldLen, LAddLen);
  827. end;
  828. end;
  829. {$IFDEF DOTNET}
  830. function MakeBlob(const ANTLMTimeStamp : System.Runtime.InteropServices.ComTypes.FileTime;
  831. const ATargetInfo : TIdBytes;const cnonce : TIdBytes) : TIdBytes;
  832. {$ELSE}
  833. function MakeBlob(const ANTLMTimeStamp : FILETIME; const ATargetInfo : TIdBytes;const cnonce : TIdBytes) : TIdBytes;
  834. {$ENDIF}
  835. begin
  836. SetLength(Result,0);
  837. //blob signature - offset 0
  838. // RespType - offset 0
  839. // HiRespType - offset 1
  840. // Reserved1 - offset 2
  841. AddByteArray( Result, NTLMv2_BLOB_Sig);
  842. // reserved - offset 4
  843. // Reserved2 - offset 4
  844. AddByteArray( Result, NTLMv2_BLOB_Res);
  845. // time - offset 8
  846. IdNTLMv2.AddUInt32(Result, ANTLMTimeStamp.dwLowDateTime );
  847. IdNTLMv2.AddUInt32(Result, ANTLMTimeStamp.dwHighDateTime );
  848. //client nonce (challange)
  849. // cnonce - offset 16
  850. IdGlobal.AppendBytes(Result,cnonce);
  851. // reserved 3
  852. // offset - offset 24
  853. AddUInt32(Result,0);
  854. // AddByteArray( Result, NTLMv2_BLOB_Res);
  855. // targetinfo - offset 28
  856. // av pairs - offset 28
  857. IdGlobal.AppendBytes(Result,ATargetInfo);
  858. // unknown (0 works)
  859. AddByteArray( Result, NTLMv2_BLOB_Res);
  860. end;
  861. function InternalCreateNTLMv2Response(var Vntlm2hash : TIdBytes;
  862. const AUsername, ADomain, APassword : String;
  863. const ATargetInfo : TIdBytes;
  864. const ATimestamp : FILETIME;
  865. const cnonce, nonce : TIdBytes): TIdBytes;
  866. var
  867. LLmUserDom : TIdBytes;
  868. Blob : TIdBytes;
  869. LEncoding: IIdTextEncoding;
  870. LHMac: TIdHMACMD5;
  871. begin
  872. LEncoding := IndyTextEncoding_UTF16LE;
  873. LLmUserDom := LEncoding.GetBytes(UpperCase(AUsername));
  874. AppendBytes(LLmUserDom, LEncoding.GetBytes(ADomain));
  875. LEncoding := nil;
  876. LHMac := TIdHMACMD5.Create;
  877. {$IFNDEF USE_OBJECT_ARC}
  878. try
  879. {$ENDIF}
  880. LHMac.Key := NTOWFv1(APassword);
  881. Vntlm2hash := LHMac.HashValue(LLmUserDom);
  882. {$IFNDEF USE_OBJECT_ARC}
  883. finally
  884. LHMac.Free;
  885. end;
  886. {$ENDIF}
  887. Blob := MakeBlob(ATimestamp,ATargetInfo,cnonce);
  888. LHMac := TIdHMACMD5.Create;
  889. {$IFNDEF USE_OBJECT_ARC}
  890. try
  891. {$ENDIF}
  892. LHMac.Key := Vntlm2hash;
  893. Result := LHMac.HashValue(ConcateBytes(nonce,Blob));
  894. {$IFNDEF USE_OBJECT_ARC}
  895. finally
  896. LHMac.Free;
  897. end;
  898. {$ENDIF}
  899. AppendBytes(Result,Blob);
  900. end;
  901. function CreateNTLMv2Response(var Vntlm2hash : TIdBytes;
  902. const AUsername, ADomain, APassword : String;
  903. const TargetName, ATargetInfo : TIdBytes;
  904. const cnonce, nonce : TIdBytes): TIdBytes;
  905. begin
  906. Result := InternalCreateNTLMv2Response(Vntlm2hash, AUsername, ADomain, APassword, ATargetInfo, NowAsFileTime,cnonce, nonce);
  907. end;
  908. function LMUserSessionKey(const AHash : TIdBytes) : TIdBytes;
  909. {$IFDEF USE_INLINE} inline; {$ENDIF}
  910. // 1. The 16-byte LM hash (calculated previously) is truncated to 8 bytes.
  911. // 2. This is null-padded to 16 bytes. This value is the LM User Session Key.
  912. begin
  913. SetLength(Result,16);
  914. FillBytes(Result,16,0);
  915. CopyTIdBytes(AHash,0,Result,0,8);
  916. end;
  917. function UserNTLMv1SessionKey(const AHash : TIdBytes) : TIdBytes;
  918. {$IFDEF USE_INLINE} inline; {$ENDIF}
  919. var
  920. LHash: TIdHashMessageDigest4;
  921. begin
  922. CheckMD4Permitted;
  923. LHash := TIdHashMessageDigest4.Create;
  924. {$IFNDEF USE_OBJECT_ARC}
  925. try
  926. {$ENDIF}
  927. Result := LHash.HashBytes(AHash);
  928. {$IFNDEF USE_OBJECT_ARC}
  929. finally
  930. LHash.Free;
  931. end;
  932. {$ENDIF}
  933. end;
  934. function UserLMv2SessionKey(const AHash : TIdBytes; const ABlob : TIdBytes; ACNonce : TIdBytes) : TIdBytes;
  935. {$IFDEF USE_INLINE} inline; {$ENDIF}
  936. var
  937. LBuf : TIdBytes;
  938. LHMac: TIdHMACMD5;
  939. begin
  940. LBuf := ABlob;
  941. AppendBytes(LBuf,ACNonce);
  942. LHMac := TIdHMACMD5.Create;
  943. {$IFNDEF USE_OBJECT_ARC}
  944. try
  945. {$ENDIF}
  946. LHMac.Key := AHash;
  947. Result := LHMac.HashValue(LHMac.HashValue(LBuf));
  948. {$IFNDEF USE_OBJECT_ARC}
  949. finally
  950. LHMac.Free;
  951. end;
  952. {$ENDIF}
  953. end;
  954. function UserNTLMv2SessionKey(const AHash : TIdBytes; const ABlob : TIdBytes; const AServerNonce : TIdBytes) : TIdBytes;
  955. {$IFDEF USE_INLINE} inline; {$ENDIF}
  956. //extremely similar to the above except that the nonce is used.
  957. begin
  958. Result := UserLMv2SessionKey(AHash,ABlob,AServerNonce);
  959. end;
  960. function UserNTLM2SessionSecSessionKey(const ANTLMv1SessionKey : TIdBytes; const AServerNonce : TIdBytes): TIdBytes;
  961. {$IFDEF USE_INLINE} inline; {$ENDIF}
  962. var
  963. LHash: TIdHMACMD5;
  964. begin
  965. LHash := TIdHMACMD5.Create;
  966. {$IFNDEF USE_OBJECT_ARC}
  967. try
  968. {$ENDIF}
  969. LHash.Key := ANTLMv1SessionKey;
  970. Result := LHash.HashValue(AServerNonce);
  971. {$IFNDEF USE_OBJECT_ARC}
  972. finally
  973. LHash.Free;
  974. end;
  975. {$ENDIF}
  976. end;
  977. function LanManagerSessionKey(const ALMHash : TIdBytes) : TIdBytes;
  978. var
  979. LKey : TIdBytes;
  980. ks : des_key_schedule;
  981. LHash8 : TIdBytes;
  982. begin
  983. LHash8 := ALMHash;
  984. SetLength(LHash8,8);
  985. SetLength(LKey,14);
  986. FillChar(LKey,14,$bd);
  987. CopyTIdBytes(LHash8,0,LKey,0,8);
  988. SetLength(Result,16);
  989. setup_des_key(pdes_cblock(@LKey[0])^, ks);
  990. DES_ecb_encrypt(@LHash8, pconst_des_cblock(@Result[0]), ks, DES_ENCRYPT);
  991. setup_des_key(pdes_cblock(@LKey[7])^, ks);
  992. DES_ecb_encrypt(@LHash8, pconst_des_cblock(@Result[8]), ks, DES_ENCRYPT);
  993. end;
  994. function SetupLMv2Response(var VntlmHash : TIdBytes; const AUsername, ADomain : String; const APassword : String; cnonce, AServerNonce : TIdBytes): TIdBytes;
  995. var
  996. LLmUserDom : TIdBytes;
  997. LChall : TIdBytes;
  998. LEncoding: IIdTextEncoding;
  999. LHMac: TIdHMACMD5;
  1000. begin
  1001. LEncoding := IndyTextEncoding_UTF16LE;
  1002. LLmUserDom := LEncoding.GetBytes(UpperCase(AUsername));
  1003. AppendBytes(LLmUserDom, LEncoding.GetBytes(ADomain));
  1004. LEncoding := nil;
  1005. LHMac := TIdHMACMD5.Create;
  1006. {$IFNDEF USE_OBJECT_ARC}
  1007. try
  1008. {$ENDIF}
  1009. LHMac.Key := NTOWFv1(APassword);
  1010. VntlmHash := LHMac.HashValue(LLmUserDom);
  1011. {$IFNDEF USE_OBJECT_ARC}
  1012. finally
  1013. LHMac.Free;
  1014. end;
  1015. {$ENDIF}
  1016. LChall := AServerNonce;
  1017. IdGlobal.AppendBytes(LChall,cnonce);
  1018. LHMac := TIdHMACMD5.Create;
  1019. {$IFNDEF USE_OBJECT_ARC}
  1020. try
  1021. {$ENDIF}
  1022. LHMac.Key := vntlmhash;
  1023. Result := LHMac.HashValue(LChall);
  1024. {$IFNDEF USE_OBJECT_ARC}
  1025. finally
  1026. LHMac.Free;
  1027. end;
  1028. {$ENDIF}
  1029. AppendBytes(Result,cnonce);
  1030. end;
  1031. //function SetupLMResponse(const APassword : String; nonce : TIdBytes): TIdBytes;
  1032. function CreateModNTLMv1Response(var Vntlmseshash : TIdBytes; const AUsername : String; const APassword : String; cnonce, nonce : TIdBytes; var LMFeild : TIdBytes): TIdBytes;
  1033. var
  1034. LChall, LTmp : TIdBytes;
  1035. lntlmseshash : TIdBytes;
  1036. LPassHash : TIdBytes;
  1037. LHash: TIdHashMessageDigest5;
  1038. begin
  1039. CheckMD5Permitted;
  1040. //LM feild value for Type3 message
  1041. SetLength(LMFeild,24);
  1042. FillBytes( LMFeild,24, 0);
  1043. IdGlobal.CopyTIdBytes(cnonce,0,LMFeild,0,8);
  1044. //
  1045. LChall := nonce;
  1046. IdGlobal.AppendBytes(LChall,cnonce);
  1047. LHash := TIdHashMessageDigest5.Create;
  1048. {$IFNDEF USE_OBJECT_ARC}
  1049. try
  1050. {$ENDIF}
  1051. Vntlmseshash := LHash.HashBytes(LChall);
  1052. //we do this copy because we may need the value later.
  1053. lntlmseshash := Vntlmseshash;
  1054. {$IFNDEF USE_OBJECT_ARC}
  1055. finally
  1056. LHash.Free;
  1057. end;
  1058. {$ENDIF}
  1059. SetLength(lntlmseshash,8);
  1060. SetLength(LPassHash,21);
  1061. FillBytes( LPassHash,21, 0);
  1062. LTmp := NTOWFv1(APassword);
  1063. IdGlobal.CopyTIdBytes(LTmp,0,LPassHash,0,Length(LTmp));
  1064. {$IFNDEF DOTNET}
  1065. SetLength(Result,24);
  1066. DESL( LPassHash,lntlmseshash, Result);
  1067. // DESL(PDes_cblock(@LPassHash[0]), lntlmseshash, Pdes_key_schedule(@Result[0]));
  1068. {$ELSE}
  1069. DESL( LPassHash,ntlmseshash, Result);
  1070. {$ENDIF}
  1071. end;
  1072. //Todo: This does not match the results from
  1073. //http://davenport.sourceforge.net/ntlm.html
  1074. function TDateTimeToNTLMTime(const ADateTime : TDateTime):Int64;
  1075. {$IFDEF USE_INLINE}inline;{$ENDIF}
  1076. begin
  1077. Result := DateTimeToUnix((ADateTime+11644473600)* 10000);
  1078. end;
  1079. function BuildType1Msg(const ADomain : String = ''; const AHost : String = ''; const ALMCompatibility : UInt32 = 0) : TIdBytes;
  1080. var
  1081. LDomain, LWorkStation: TIdBytes;
  1082. LDomLen, LWorkStationLen: UInt16;
  1083. LFlags : UInt32;
  1084. LEncoding: IIdTextEncoding;
  1085. begin
  1086. SetLength(Result,0);
  1087. LEncoding := IndyTextEncoding_OSDefault;
  1088. LDomain := LEncoding.GetBytes(ADomain); //UpperCase(ADomain));
  1089. LWorkStation := LEncoding.GetBytes(AHost); //UpperCase(AHost));
  1090. LEncoding := nil;
  1091. LFlags := IdNTLM_TYPE1_FLAGS_LC2;
  1092. case ALMCompatibility of
  1093. 0, 1 : LFlags := IdNTLM_TYPE1_FLAGS;
  1094. end;
  1095. LDomLen := Length(LDomain);
  1096. if LDomLen > 0 then begin
  1097. LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
  1098. end;
  1099. LWorkStationLen := Length(LWorkStation);
  1100. if LWorkStationLen > 0 then begin
  1101. LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
  1102. end;
  1103. //signature
  1104. AppendBytes(Result,IdNTLM_SSP_SIG);
  1105. //type
  1106. AddUInt32(Result,IdNTLM_TYPE1_MARKER);
  1107. //flags
  1108. AddUInt32(Result,LFlags);
  1109. //Supplied Domain security buffer
  1110. // - length
  1111. AddUInt16(Result,LDomLen);
  1112. // - allocated space
  1113. AddUInt16(Result,LDomLen);
  1114. // - offset
  1115. AddUInt32(Result,LWorkStationLen+$20);
  1116. //Supplied Workstation security buffer (host)
  1117. // - length
  1118. AddUInt16(Result,LWorkStationLen);
  1119. // - allocated space
  1120. AddUInt16(Result,LWorkStationLen);
  1121. // - offset
  1122. if LWorkStationLen > 0 then begin
  1123. AddUInt32(Result,$20);
  1124. end else begin
  1125. AddUInt32(Result,$08);
  1126. end;
  1127. // Supplied Workstation (host)
  1128. if LWorkStationLen > 0 then begin
  1129. AppendBytes(Result,LWorkStation,0,LWorkStationLen);
  1130. end;
  1131. // Supplied Domain
  1132. if LDomLen > 0 then begin
  1133. AppendBytes(Result,LDomain,0,LDomLen);
  1134. end;
  1135. end;
  1136. procedure ReadType2Msg(const AMsg : TIdBytes; var VFlags : UInt32; var VTargetName : TIdBytes; var VTargetInfo : TIdBytes; var VNonce : TIdBytes );
  1137. var
  1138. LLen : UInt16;
  1139. LOfs : UInt32;
  1140. begin
  1141. //extract flags
  1142. VFlags := LittleEndianToHost(BytesToUInt32(AMsg,IdNTLM_TYPE2_FLAGS_OFS));
  1143. //extract target name
  1144. // - security buffer
  1145. LLen := LittleEndianToHost( BytesToUInt16(AMsg,IdNTLM_TYPE2_TNAME_LEN_OFS));
  1146. LOfs := LittleEndianToHost( BytesToUInt32(AMsg,IdNTLM_TYPE2_TNAME_OFFSET_OFS));
  1147. // - the buffer itself
  1148. SetLength(VTargetName,LLen);
  1149. CopyTIdBytes(AMsg,LOfs,VTargetName,0,LLen);
  1150. //extract targetinfo
  1151. //Note that we should ignore TargetInfo if it is not required.
  1152. if VFlags and IdNTLMSSP_NEGOTIATE_TARGET_INFO > 0 then begin
  1153. // - security buffer
  1154. LLen := LittleEndianToHost( BytesToUInt16(AMsg,IdNTLM_TYPE2_TINFO_LEN_OFS));
  1155. LOfs := LittleEndianToHost( BytesToUInt32(AMsg,IdNTLM_TYPE2_TINFO_OFFSET_OFS));
  1156. // - the buffer itself
  1157. SetLength(VTargetInfo,LLen);
  1158. CopyTIdBytes(AMsg,LOfs,VTargetInfo,0,LLen);
  1159. end else begin
  1160. SetLength(VTargetInfo,0);
  1161. end;
  1162. //extract nonce
  1163. SetLength(VNonce,IdNTLM_NONCE_LEN);
  1164. CopyTIdBytes(AMsg,IdNTLM_TYPE2_NONCE_OFS,VNonce,0,IdNTLM_NONCE_LEN);
  1165. end;
  1166. function CreateData(const ABytes : TIdBytes; const AOffset : UInt32; var VBuffer : TIdBytes) : UInt32;
  1167. //returns the next buffer value
  1168. //adds security value ptr to Vbuffer
  1169. var
  1170. LLen : UInt16;
  1171. begin
  1172. LLen := Length(ABytes);
  1173. // - length
  1174. AddUInt16(VBuffer,LLen);
  1175. // - allocated space
  1176. AddUInt16(VBuffer,LLen);
  1177. // - offset
  1178. AddUInt32(VBuffer,AOffset);
  1179. Result := AOffset + Llen;
  1180. end;
  1181. function GenerateCNonce : TIdBytes;
  1182. begin
  1183. SetLength(Result,8);
  1184. Randomize;
  1185. Result[0] := Random(127)+1;
  1186. Result[1] := Random(127)+1;
  1187. Result[2] := Random(127)+1;
  1188. Result[3] := Random(127)+1;
  1189. Result[4] := Random(127)+1;
  1190. Result[5] := Random(127)+1;
  1191. Result[6] := Random(127)+1;
  1192. Result[7] := Random(127)+1;
  1193. end;
  1194. const
  1195. IdNTLM_IGNORE_TYPE_2_3_MASK = not
  1196. (IdNTLMSSP_TARGET_TYPE_DOMAIN or
  1197. IdNTLMSSP_TARGET_TYPE_SERVER or
  1198. IdNTLMSSP_TARGET_TYPE_SHARE);
  1199. function BuildType3Msg(const ADomain, AHost, AUsername, APassword : String;
  1200. const AFlags : UInt32; const AServerNonce : TIdBytes;
  1201. const ATargetName, ATargetInfo : TIdBytes;
  1202. const ALMCompatibility : UInt32 = 0) : TIdBytes;
  1203. var
  1204. LDom, LHost, LUser, LLMData, LNTLMData, LCNonce : TIdBytes;
  1205. llmhash, lntlmhash : TIdBytes;
  1206. ll_len, ln_len, ld_len, lh_len, lu_len : UInt16;
  1207. ll_ofs, ln_ofs, ld_ofs, lh_ofs, lu_ofs : UInt32;
  1208. LFlags : UInt32;
  1209. LEncoding: IIdTextEncoding;
  1210. begin
  1211. LFlags := AFlags and IdNTLM_IGNORE_TYPE_2_3_MASK;
  1212. if AFlags and IdNTLMSSP_REQUEST_TARGET > 0 then begin
  1213. LFlags := LFlags or IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
  1214. end;
  1215. if LFlags and IdNTLMSSP_NEGOTIATE_UNICODE <> 0 then begin
  1216. LEncoding := IndyTextEncoding_UTF16LE;
  1217. if LFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED > 0 then begin
  1218. if Length(ATargetName) > 0 then begin
  1219. LDom := ATargetName;
  1220. end else begin
  1221. LDom := LEncoding.GetBytes(UpperCase(ADomain));
  1222. end;
  1223. end;
  1224. if LFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED > 0 then begin
  1225. LHost := LEncoding.GetBytes(UpperCase(AHost));
  1226. end;
  1227. LUser := LEncoding.GetBytes(UpperCase(AUsername));
  1228. LEncoding := nil;
  1229. end else begin
  1230. if LFlags and IdNTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED > 0 then begin
  1231. LDom := ToBytes(UpperCase(ADomain));
  1232. end;
  1233. if LFlags and IdNTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED > 0 then begin
  1234. LHost := ToBytes(UpperCase(AHost));
  1235. end;
  1236. LUser := ToBytes(UpperCase(AUsername));
  1237. end;
  1238. if (ALMCompatibility < 3) and
  1239. (AFlags and IdNTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY > 0) then
  1240. begin
  1241. LCNonce := GenerateCNonce;
  1242. LNTLMData := CreateModNTLMv1Response(lntlmhash,AUserName,APassword,LCNonce,AServerNonce,LLMData);
  1243. // LLMData := IdNTLMv2.SetupLMv2Response(AUsername,ADomain,APassword,LCNonce,AServerNonce);
  1244. // LNTLMData := CreateNTLMv2Response(AUserName,ADomain,APassword,ATargetName,ATargetName, ATargetInfo,LCNonce);
  1245. end else begin
  1246. case ALMCompatibility of
  1247. 0 :
  1248. begin
  1249. if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
  1250. begin
  1251. SetLength(LLMData,0);
  1252. end
  1253. else
  1254. begin
  1255. LLMData := SetupLMResponse(llmhash, APassword, AServerNonce);
  1256. end;
  1257. LNTLMData := CreateNTLMResponse(lntlmhash, APassword, AServerNonce);
  1258. end;
  1259. 1 :
  1260. begin
  1261. if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
  1262. begin
  1263. SetLength(LLMData,0);
  1264. end
  1265. else
  1266. begin
  1267. LLMData := SetupLMResponse(llmhash, APassword, AServerNonce);
  1268. end;
  1269. LNTLMData := CreateNTLMResponse(lntlmhash,APassword, AServerNonce);
  1270. end;
  1271. 2 : //Send NTLM response only
  1272. begin
  1273. LNTLMData := CreateNTLMResponse(lntlmhash,APassword, AServerNonce);
  1274. if AFlags and IdNTLMSSP_NEGOTIATE_NT_ONLY <> 0 then
  1275. begin
  1276. SetLength(LLMData,0);
  1277. end
  1278. else
  1279. begin
  1280. LLMData := LNTLMData;
  1281. // LLMData := SetupLMResponse(APassword, ANonce);
  1282. end;
  1283. end;
  1284. 3,4,5 : //Send NTLMv2 response only
  1285. begin
  1286. // LFlags := LFlags and (not IdNTLMSSP_NEGOTIATE_NTLM);
  1287. LCNonce := GenerateCNonce;
  1288. LLMData := IdNTLMv2.SetupLMv2Response(llmhash,AUsername,ADomain,APassword,LCNonce,AServerNonce);
  1289. LNTLMData := CreateNTLMv2Response(lntlmhash,AUserName,ADomain,APassword,ATargetName,ATargetInfo,LCNonce,AServerNonce);
  1290. end;
  1291. // LCNonce := GenerateCNonce;
  1292. // LNTLMData := IdNTLMv2.CreateModNTLMv1Response(AUserName,APassword,LCNonce,ANonce,LLMData);
  1293. end;
  1294. end;
  1295. //calculations for security buffer pointers
  1296. //We do things this way because the security buffers are in a different order
  1297. //than the data buffers themselves. In theory, you could change it but it's
  1298. //not a good idea.
  1299. ll_len := Length(LLMData);
  1300. ln_len := Length(LNTLMData);
  1301. ld_len := Length(LDom);
  1302. lh_len := Length(LHost);
  1303. lu_len := Length(LUser);
  1304. LFlags := LFlags and (not IdNTLMSSP_NEGOTIATE_VERSION);
  1305. ld_ofs := IdNTLM_TYPE3_DOM_OFFSET;
  1306. { if LFlags and IdNTLMSSP_NEGOTIATE_VERSION <> 0 then
  1307. begin
  1308. ld_ofs := IdNTLM_TYPE3_DOM_OFFSET + 8;
  1309. AppendByte(Result, IdNTLM_WINDOWS_MAJOR_VERSION_6);
  1310. AppendByte(Result, IdNTLM_WINDOWS_MINOR_VERSION_0);
  1311. AddUInt16(Result,IdNTLM_WINDOWS_BUILD_ORIG_VISTA);
  1312. AddUInt32(Result,$F);
  1313. end; }
  1314. lu_ofs := ld_len + ld_ofs;
  1315. lh_ofs := lu_len + lu_ofs;
  1316. ll_ofs := lh_len + lh_ofs;
  1317. ln_ofs := ll_len + ll_ofs;
  1318. SetLength(Result,0);
  1319. // 0 - signature
  1320. AppendBytes(Result,IdNTLM_SSP_SIG);
  1321. // 8 - type
  1322. AddUInt32(Result,IdNTLM_TYPE3_MARKER);
  1323. //12 - LM Response Security Buffer:
  1324. // - length
  1325. AddUInt16(Result,ll_len);
  1326. // - allocated space
  1327. AddUInt16(Result,ll_len);
  1328. // - offset
  1329. AddUInt32(Result,ll_ofs);
  1330. //20 - NTLM Response Security Buffer:
  1331. // - length
  1332. AddUInt16(Result,ln_len);
  1333. // - allocated space
  1334. AddUInt16(Result,ln_len);
  1335. // - offset
  1336. AddUInt32(Result,ln_ofs);
  1337. //28 - Domain Name Security Buffer: (target)
  1338. // - length
  1339. AddUInt16(Result,ld_len);
  1340. // - allocated space
  1341. AddUInt16(Result,ld_len);
  1342. // - offset
  1343. AddUInt32(Result,ld_ofs);
  1344. //36 - User Name Security Buffer:
  1345. // - length
  1346. AddUInt16(Result,lu_len);
  1347. // - allocated space
  1348. AddUInt16(Result,lu_len);
  1349. // - offset
  1350. AddUInt32(Result,lu_ofs);
  1351. //44 - Workstation Name (host) Security Buffer:
  1352. // - length
  1353. AddUInt16(Result,lh_len);
  1354. // - allocated space
  1355. AddUInt16(Result,lh_len);
  1356. // - offset
  1357. AddUInt32(Result,lh_ofs);
  1358. //52 - Session Key Security Buffer:
  1359. // - length
  1360. AddUInt16(Result,0);
  1361. // - allocated space
  1362. AddUInt16(Result,0);
  1363. // - offset
  1364. AddUInt32(Result,ln_ofs+ln_len);
  1365. //60 - Flags:
  1366. //The flags feild is strictly optional. About the only time it matters is
  1367. //with Datagram authentication.
  1368. AddUInt32(Result,LFlags);
  1369. if ld_len > 0 then
  1370. begin
  1371. //64 - Domain Name Data ("DOMAIN")
  1372. AppendBytes(Result,LDom);
  1373. end;
  1374. if lu_len >0 then
  1375. begin
  1376. //User Name Data ("user")
  1377. AppendBytes(Result,LUser);
  1378. end;
  1379. if lh_len > 0 then
  1380. begin
  1381. //Workstation Name Data (host)
  1382. AppendBytes(Result,LHost);
  1383. end;
  1384. //LM Response Data
  1385. AppendBytes(Result,LLMData);
  1386. //NTLM Response Data
  1387. AppendBytes(Result,LNTLMData);
  1388. end;
  1389. {$IFDEF TESTSUITE}
  1390. const
  1391. TEST_TARGETINFO : array [0..97] of byte = (
  1392. $02,$00,$0c,$00,$44,$00,$4f,$00,
  1393. $4d,$00,$41,$00,$49,$00,$4e,$00,
  1394. $01,$00,$0c,$00,$53,$00,$45,$00,
  1395. $52,$00,$56,$00,$45,$00,$52,$00,
  1396. $04,$00,$14,$00,$64,$00,$6f,$00,
  1397. $6d,$00,$61,$00,$69,$00,$6e,$00,
  1398. $2e,$00,$63,$00,$6f,$00,$6d,$00,
  1399. $03,$00,$22,$00,$73,$00,$65,$00,
  1400. $72,$00,$76,$00,$65,$00,$72,$00,
  1401. $2e,$00,$64,$00,$6f,$00,$6d,$00,
  1402. $61,$00,$69,$00,$6e,$00,$2e,$00,
  1403. $63,$00,$6f,$00,$6d,$00,$00,$00,
  1404. $00,$00);
  1405. {function StrToHex(const AStr : AnsiString) : AnsiString;
  1406. var
  1407. i : Integer;
  1408. begin
  1409. Result := '';
  1410. for i := 1 to Length(AStr) do begin
  1411. Result := Result + IntToHex(Ord(AStr[i]),2)+ ' ';
  1412. end;
  1413. end; }
  1414. function BytesToHex(const ABytes : array of byte) : String;
  1415. var
  1416. i : Integer;
  1417. begin
  1418. for i := Low(ABytes) to High(ABytes) do
  1419. begin
  1420. Result := Result + IntToHex(ABytes[i],2)+ ' ';
  1421. end;
  1422. end;
  1423. procedure DoDavePortTests;
  1424. var
  1425. LNonce,LCNonce, lmhash : TIdBytes;
  1426. LMResp : TIdBytes;
  1427. LTargetINfo : TIdBytes;
  1428. Ltst : String;
  1429. begin
  1430. SetLength(LNonce,8);
  1431. LNonce[0] := $01;
  1432. LNonce[1] := $23;
  1433. LNonce[2] := $45;
  1434. LNonce[3] := $67;
  1435. LNonce[4] := $89;
  1436. LNonce[5] := $ab;
  1437. LNonce[6] := $cd;
  1438. LNonce[7] := $ef;
  1439. SetLength(LCNonce,8);
  1440. LCNonce[0] := $ff;
  1441. LCNonce[1] := $ff;
  1442. LCNonce[2] := $ff;
  1443. LCNonce[3] := $00;
  1444. LCNonce[4] := $11;
  1445. LCNonce[5] := $22;
  1446. LCNonce[6] := $33;
  1447. LCNonce[7] := $44;
  1448. SetLength(LTargetInfo,Length(TEST_TARGETINFO));
  1449. CopyTIdByteArray(TEST_TARGETINFO,0,LTargetInfo,0,Length(TEST_TARGETINFO));
  1450. if ToHex(SetupLMResponse(lmhash,'SecREt01',LNonce)) <> 'C337CD5CBD44FC9782A667AF6D427C6DE67C20C2D3E77C56' then
  1451. begin
  1452. DebugOutput(BytesToHex(LNonce));
  1453. raise Exception.Create('LM Response test failed');
  1454. end;
  1455. if ToHex(CreateNTLMResponse(lmhash,'SecREt01',LNonce)) <> '25A98C1C31E81847466B29B2DF4680F39958FB8C213A9CC6' then
  1456. begin
  1457. raise Exception.Create('NTLM Response test failed');
  1458. end;
  1459. if ToHex(CreateModNTLMv1Response(lmhash,'user','SecREt01',LCNonce,LNonce,LMResp)) <> '10D550832D12B2CCB79D5AD1F4EED3DF82ACA4C3681DD455' then
  1460. begin
  1461. raise Exception.Create ('NTLM2 Session Response failed');
  1462. end;
  1463. if ToHex(LMResp) <> 'FFFFFF001122334400000000000000000000000000000000' then
  1464. begin
  1465. raise Exception.Create ('LM Response for NTLM2 reponse failed');
  1466. end;
  1467. if ToHex(SetupLMv2Response(lmhash,'user','DOMAIN','SecREt01',LCNonce,LNonce)) <> 'D6E6152EA25D03B7C6BA6629C2D6AAF0FFFFFF0011223344' then
  1468. begin
  1469. raise Exception.Create ( 'LMv2 Response failed');
  1470. end;
  1471. Ltst := ToHex(InternalCreateNTLMv2Response(lmhash,'user','DOMAIN','SecREt01',LTargetInfo,UnixTimeToFileTime(1055844000),LCNonce,LNonce ));
  1472. if LTst <>
  1473. 'CBABBCA713EB795D04C97ABC01EE4983'+
  1474. '01010000000000000090D336B734C301'+
  1475. 'FFFFFF00112233440000000002000C00' +
  1476. '44004F004D00410049004E0001000C00' +
  1477. '53004500520056004500520004001400' +
  1478. '64006F006D00610069006E002E006300' +
  1479. '6F006D00030022007300650072007600' +
  1480. '650072002E0064006F006D0061006900' +
  1481. '6E002E0063006F006D00000000000000' +
  1482. '0000' then
  1483. begin
  1484. raise Exception.Create ('NTLMv2 Response failed' );
  1485. end;
  1486. end;
  1487. function ConstArray(const AArray : array of byte) : TIdBytes;
  1488. var
  1489. i : Integer;
  1490. begin
  1491. SetLength(Result,0);
  1492. for i := Low(AArray) to High(AArray) do begin
  1493. AppendByte(Result,AArray[i]);
  1494. end;
  1495. end;
  1496. {
  1497. Microsoft tests
  1498. User
  1499. 0000000: 55 00 73 00 65 00 72 00 U.s.e.r.
  1500. 0000000: 55 00 53 00 45 00 52 00 U.S.E.R.
  1501. 0000000: 55 73 65 72 User
  1502. UserDom
  1503. 0000000: 44 00 6f 00 6d 00 61 00 69 00 6e 00 D.o.m.a.i.n
  1504. Password
  1505. 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.
  1506. 0000000: 50 41 53 53 57 4f 52 44 00 00 00 00 00 00 PASSWORD......
  1507. Server Name
  1508. 00000000: 53 00 65 00 72 00 76 00 65 00 72 00 S.e.r.v.e.r.
  1509. Workstation Name
  1510. 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.
  1511. Random Session Key
  1512. 0000000: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
  1513. Time
  1514. 0000000: 00 00 00 00 00 00 00 00 ........
  1515. Client Challange
  1516. 0000000: aa aa aa aa aa aa aa aa ........
  1517. Server Challange
  1518. 0000000: 01 23 45 67 89 ab cd ef .#Eg..&#x2550;.
  1519. 4.2.2 NTLM v1 Authentication
  1520. # NTLMSSP_NEGOTIATE_KEY_EXCH
  1521. # NTLMSSP_NEGOTIATE_56
  1522. # NTLMSSP_NEGOTIATE_128
  1523. # NTLMSSP_NEGOTIATE_VERSION
  1524. # NTLMSSP_TARGET_TYPE_SERVER
  1525. # NTLMSSP_NEGOTIATE_ALWAYS_SIGN
  1526. # NTLM NTLMSSP_NEGOTIATE_NTLM
  1527. # NTLMSSP_NEGOTIATE_SEAL
  1528. # NTLMSSP_NEGOTIATE_SIGN
  1529. # NTLM_NEGOTIATE_OEM
  1530. # NTLMSSP_NEGOTIATE_UNICOD
  1531. NTLMv1 data flags
  1532. 33 82 02 e2
  1533. }
  1534. procedure DoMSTests;
  1535. var
  1536. LFlags : UInt32;
  1537. LEncoding: IIdTextEncoding;
  1538. begin
  1539. LFlags := IdNTLMSSP_NEGOTIATE_KEY_EXCH or
  1540. IdNTLMSSP_NEGOTIATE_56 or IdNTLMSSP_NEGOTIATE_128 or
  1541. IdNTLMSSP_NEGOTIATE_VERSION or IdNTLMSSP_TARGET_TYPE_SERVER or
  1542. IdNTLMSSP_NEGOTIATE_ALWAYS_SIGN or IdNTLMSSP_NEGOTIATE_NTLM or
  1543. IdNTLMSSP_NEGOTIATE_SEAL or IdNTLMSSP_NEGOTIATE_SIGN or
  1544. IdNTLM_NEGOTIATE_OEM or IdNTLMSSP_NEGOTIATE_UNICODE;
  1545. if ToHex(ToBytes(LFlags))<>'338202E2' then
  1546. begin
  1547. raise Exception.Create('MS Tests failed - NTLMv1 data flags');
  1548. end;
  1549. // if ToHex(NTOWFv1('Password') ) <> UpperCase('e52cac67419a9a224a3b108f3fa6cb6d') then
  1550. LEncoding := IndyTextEncoding_ASCII;
  1551. if ToHex(LMOWFv1(
  1552. LEncoding.GetBytes(Uppercase( 'Password')),
  1553. LEncoding.GetBytes(Uppercase( 'User')),
  1554. LEncoding.GetBytes(Uppercase( 'Domain')))) <>
  1555. Uppercase('e52cac67419a9a224a3b108f3fa6cb6d') then
  1556. begin
  1557. raise Exception.Create('MS Tests failed - LMOWFv1');
  1558. end;
  1559. end;
  1560. procedure TestNTLM;
  1561. begin
  1562. // DoMSTests;
  1563. DoDavePortTests;
  1564. end;
  1565. {$ENDIF}
  1566. initialization
  1567. SetLength(IdNTLM_SSP_SIG,8);
  1568. IdNTLM_SSP_SIG[0] :=$4e; //N
  1569. IdNTLM_SSP_SIG[1] :=$54; //T
  1570. IdNTLM_SSP_SIG[2] :=$4c; //L
  1571. IdNTLM_SSP_SIG[3] :=$4d; //M
  1572. IdNTLM_SSP_SIG[4] :=$53; //S
  1573. IdNTLM_SSP_SIG[5] :=$53; //S
  1574. IdNTLM_SSP_SIG[6] :=$50; //P
  1575. IdNTLM_SSP_SIG[7] :=$00; //#00
  1576. UnixEpoch := EncodeDate(1970, 1, 1);
  1577. end.