PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdNTLM.pas

http://github.com/lookias/ProSnooper
Pascal | 302 lines | 202 code | 52 blank | 48 comment | 4 complexity | 343c1dec3ef80a558e35991511056a28 MD5 | raw file
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 11695: IdNTLM.pas
  11. {
  12. { Rev 1.1 6/29/04 12:51:10 PM RLebeau
  13. { Updatd SetupLanManagerPassword() to check the password length before
  14. { referencing the password data
  15. }
  16. {
  17. { Rev 1.0 11/13/2002 07:58:08 AM JPMugaas
  18. }
  19. {
  20. Implementation of the NTLM authentication as specified in
  21. http://www.innovation.ch/java/ntlm.html with some fixes
  22. Author: Doychin Bondzhev (doychin@dsoft-bg.com)
  23. Copyright: (c) Chad Z. Hower and The Winshoes Working Group.
  24. S.G. 12/7/2002: - Rewrote Type 1 and Type 2 structures to be closer to the
  25. document referenced in the above URL. (Easier to read and check)
  26. - Corrected falgs accouring to bug ID 577895 and own packet traces.
  27. This was actually only an adjustment to the new data types when
  28. I rewrote the header.
  29. - Initialized structures to #0 before using.
  30. }
  31. unit IdNTLM;
  32. interface
  33. Uses
  34. IdSSLOpenSSLHeaders;
  35. Type
  36. type_1_message_header = packed record
  37. protocol: array [1..8] of Char; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize}
  38. _type: Byte; // 0x01
  39. pad : packed Array[1..3] of byte; // 0x0
  40. flags: Word; // 0xb203
  41. pad2 : packed Array[1..2] of Byte; // 0x0
  42. dom_len1: Word; // domain string length
  43. dom_len2: Word; // domain string length
  44. dom_off: LongWord; // domain string offset
  45. host_len1: Word; // host string length
  46. host_len2: Word; // host string length
  47. host_off: LongWord; // host string offset (always 0x20)
  48. end;
  49. type_2_message_header = packed record
  50. protocol: packed array [1..8] of Char; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', #0 {Do not Localize}
  51. _type: Byte; // $2
  52. Pad : packed Array[1..7] of byte; // 0x0
  53. msg_len: Word; // 0x28
  54. Pad2 : packed Array [1..2] of byte; // 0x0
  55. flags: word; // 0x8201
  56. Pad3: Packed array [1..2] of byte; // 0x0
  57. nonce: Array[1..8] of char; // nonce
  58. pad4: packed Array[1..8] of byte // 0x0
  59. end;
  60. type_3_message_header = packed record
  61. protocol: array [1..8] of Char; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize}
  62. _type: LongWord; // 0x03
  63. lm_resp_len1: Word; // LanManager response length (always 0x18)
  64. lm_resp_len2: Word; // LanManager response length (always 0x18)
  65. lm_resp_off: LongWord; // LanManager response offset
  66. nt_resp_len1: Word; // NT response length (always 0x18)
  67. nt_resp_len2: Word; // NT response length (always 0x18)
  68. nt_resp_off: LongWord; // NT response offset
  69. dom_len1: Word; // domain string length
  70. dom_len2: Word; // domain string length
  71. dom_off: LongWord; // domain string offset (always 0x40)
  72. user_len1: Word; // username string length
  73. user_len2: Word; // username string length
  74. user_off: LongWord; // username string offset
  75. host_len1: Word; // host string length
  76. host_len2: Word; // host string length
  77. host_off: LongWord; // host string offset
  78. zero: LongWord;
  79. msg_len: LongWord; // message length
  80. flags: LongWord; // 0xA0808205
  81. end;
  82. Pdes_key_schedule = ^des_key_schedule;
  83. function BuildType1Message(ADomain, AHost: String): String;
  84. function BuildType3Message(ADomain, AHost, AUsername: WideString; APassword, ANonce: String): String;
  85. implementation
  86. Uses
  87. SysUtils,
  88. IdHash,
  89. IdHashMessageDigest,
  90. IdCoderMIME;
  91. {/*
  92. * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
  93. * The key schedule ks is also set.
  94. */}
  95. procedure setup_des_key(key_56: des_cblock; Var ks: des_key_schedule);
  96. Var
  97. key: des_cblock;
  98. begin
  99. key[0] := key_56[0];
  100. key[1] := ((key_56[0] SHL 7) and $FF) or (key_56[1] SHR 1);
  101. key[2] := ((key_56[1] SHL 6) and $FF) or (key_56[2] SHR 2);
  102. key[3] := ((key_56[2] SHL 5) and $FF) or (key_56[3] SHR 3);
  103. key[4] := ((key_56[3] SHL 4) and $FF) or (key_56[4] SHR 4);
  104. key[5] := ((key_56[4] SHL 3) and $FF) or (key_56[5] SHR 5);
  105. key[6] := ((key_56[5] SHL 2) and $FF) or (key_56[6] SHR 6);
  106. key[7] := (key_56[6] SHL 1) and $FF;
  107. iddes_set_odd_parity(key);
  108. iddes_set_key(key, ks);
  109. end;
  110. {/*
  111. * takes a 21 byte array and treats it as 3 56-bit DES keys. The
  112. * 8 byte plaintext is encrypted with each key and the resulting 24
  113. * bytes are stored in the results array.
  114. */}
  115. procedure calc_resp(keys: PDES_cblock; Anonce: String; results: Pdes_key_schedule);
  116. Var
  117. ks: des_key_schedule;
  118. nonce: des_cblock;
  119. begin
  120. setup_des_key(keys^, ks);
  121. move(ANonce[1], nonce, 8);
  122. iddes_ecb_encrypt(nonce, Pdes_cblock(results)^, ks, OPENSSL_DES_ENCRYPT);
  123. setup_des_key(PDES_cblock(Integer(keys) + 7)^, ks);
  124. iddes_ecb_encrypt(nonce, Pdes_cblock(Integer(results) + 8)^, ks, OPENSSL_DES_ENCRYPT);
  125. setup_des_key(PDES_cblock(Integer(keys) + 14)^, ks);
  126. iddes_ecb_encrypt(nonce, Pdes_cblock(Integer(results) + 16)^, ks, OPENSSL_DES_ENCRYPT);
  127. end;
  128. Const
  129. Magic: des_cblock = ($4B, $47, $53, $21, $40, $23, $24, $25 );
  130. //* setup LanManager password */
  131. function SetupLanManagerPassword(APassword, nonce: String): String;
  132. Var
  133. lm_hpw: array[1..21] of Char;
  134. lm_pw: array[1..14] of Char;
  135. idx, len: Integer;
  136. ks: des_key_schedule;
  137. lm_resp: array [1..24] of Char;
  138. begin
  139. APassword := Copy(UpperCase(APassword), 1, 14);
  140. len := Length(APassword);
  141. if (len > 0) then begin
  142. Move(APassword[1], lm_pw, len);
  143. end;
  144. if len < 14 then begin
  145. for idx := len + 1 to 14 do lm_pw[idx] := #0;
  146. end;
  147. //* create LanManager hashed password */
  148. setup_des_key(pdes_cblock(@lm_pw[1])^, ks);
  149. iddes_ecb_encrypt(magic, pdes_cblock(@lm_hpw[1])^, ks, OPENSSL_DES_ENCRYPT);
  150. setup_des_key(pdes_cblock(integer(@lm_pw[1]) + 7)^, ks);
  151. iddes_ecb_encrypt(magic, pdes_cblock(integer(@lm_hpw[1]) + 8)^, ks, OPENSSL_DES_ENCRYPT);
  152. FillChar(lm_hpw[17], 5, 0);
  153. calc_resp(PDes_cblock(@lm_hpw[1]), nonce, Pdes_key_schedule(@lm_resp[1]));
  154. result := lm_resp;
  155. end;
  156. function BuildUnicode(S: String): string;
  157. Var
  158. i: integer;
  159. S1: String;
  160. begin
  161. S1 := S;
  162. for i := 1 to Length(S) do
  163. Insert(#0, S1, i * 2);
  164. result := S1;
  165. end;
  166. //* create NT hashed password */
  167. function CreateNTPassword(APassword, nonce: String): String;
  168. Var
  169. nt_pw: String;
  170. nt_hpw: array [1..21] of Char;
  171. nt_hpw128: T4x4LongWordRecord absolute nt_hpw;
  172. MD4_CTX: TIdHashMessageDigest4;
  173. nt_resp: array [1..24] of Char;
  174. begin
  175. nt_pw := BuildUnicode(APassword);
  176. MD4_CTX := TIdHashMessageDigest4.Create;
  177. nt_hpw128 := MD4_CTX.HashValue(nt_pw);
  178. MD4_CTX.Free;
  179. FillChar(nt_hpw[17], 5, 0);
  180. calc_resp(pdes_cblock(@nt_hpw[1]), nonce, Pdes_key_schedule(@nt_resp[1]));
  181. result := nt_resp;
  182. end;
  183. function BuildType1Message(ADomain, AHost: String): String;
  184. Var
  185. Type_1_Message: type_1_message_header;
  186. S: String;
  187. begin
  188. FillChar(Type_1_Message, SizeOf(Type_1_Message), #0);
  189. with Type_1_Message do
  190. begin
  191. protocol := 'NTLMSSP'#0; {Do not Localize}
  192. _type := 1;
  193. // S.G. 12/7/2002: Changed the flag to $B207 (from BugID 577895 and packet trace)
  194. flags := $b207; //was $A000B207; //b203;
  195. dom_len1 := Length(ADomain);
  196. dom_len2 := Length(ADomain);
  197. // dom_off := 0;
  198. dom_off := Length(AHost) + 32;
  199. host_len1 := Length(AHost);
  200. host_len2 := Length(AHost);
  201. host_off := 32;
  202. end;
  203. SetLength(S, SizeOf(Type_1_Message));
  204. UniqueString(S);
  205. Move(Type_1_Message, S[1], SizeOf(Type_1_Message));
  206. result := TIdEncoderMIME.EncodeString(S + UpperCase(AHost) + UpperCase(ADomain));
  207. end;
  208. function BuildType3Message(ADomain, AHost, AUsername: WideString; APassword, ANonce: String): String;
  209. Var
  210. type3: type_3_message_header;
  211. S: String;
  212. lm_password: String;
  213. nt_password: String;
  214. begin
  215. lm_password := SetupLanManagerPassword(APassword, ANonce);
  216. nt_password := CreateNTPassword(APassword, ANonce);
  217. ADomain := BuildUnicode(UpperCase(ADomain));
  218. AHost := BuildUnicode(UpperCase(AHost));
  219. AUsername := BuildUnicode(AUsername);
  220. with Type3 do begin
  221. protocol := 'NTLMSSP'#0; {Do not Localize}
  222. _type := 3;
  223. lm_resp_len1 := $18;// S.G. 12/7/2002: was: Length(lm_password); (from BugID 577895)
  224. lm_resp_len2 := $18;// S.G. 12/7/2002: was: Length(lm_password); (from BugID 577895)
  225. lm_resp_off := Length(ADomain) + Length(AUsername) + Length(AHost) + $40;
  226. nt_resp_len1 := $18;// S.G. 12/7/2002: was: Length(nt_password); (from BugID 577895)
  227. nt_resp_len2 := $18;// S.G. 12/7/2002: was: Length(nt_password); (from BugID 577895)
  228. nt_resp_off := Length(ADomain) + Length(AUsername) + Length(AHost) + Length(lm_password) + $40;
  229. dom_len1 := Length(ADomain);
  230. dom_len2 := Length(ADomain);
  231. dom_off := $40;
  232. user_len1 := Length(AUsername);
  233. user_len2 := Length(AUsername);
  234. user_off := Length(ADomain) + $40;
  235. host_len1 := Length(AHost);
  236. host_len2 := Length(AHost);
  237. host_off := Length(ADomain) + Length(AUsername) + $40;
  238. zero := 0;
  239. msg_len := SIZEOf(Type3) + Length(ADomain) + Length(AUsername) + Length(Ahost) + Length(lm_password) + Length(nt_password);
  240. flags := $018205; // S.G. 12/7/2002: was: flags := $A0808205; (from BugID 577895 and packet trace)
  241. end;
  242. SetLength(S, SizeOf(Type3));
  243. Move(Type3, S[1], SizeOf(Type3));
  244. result := TIdEncoderMIME.EncodeString(S + ADomain + AUsername + AHost + lm_password + nt_password);
  245. end;
  246. end.