NtlmPasswordAuthentication.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System;
  18. using SharpCifs.Util;
  19. using SharpCifs.Util.Sharpen;
  20. namespace SharpCifs.Smb
  21. {
  22. /// <summary>This class stores and encrypts NTLM user credentials.</summary>
  23. /// <remarks>
  24. /// This class stores and encrypts NTLM user credentials. The default
  25. /// credentials are retrieved from the <tt>jcifs.smb.client.domain</tt>,
  26. /// <tt>jcifs.smb.client.username</tt>, and <tt>jcifs.smb.client.password</tt>
  27. /// properties.
  28. /// <p>
  29. /// Read <a href="../../../authhandler.html">jCIFS Exceptions and
  30. /// NtlmAuthenticator</a> for related information.
  31. /// </remarks>
  32. public sealed class NtlmPasswordAuthentication : Principal
  33. {
  34. private static readonly int LmCompatibility = Config.GetInt("jcifs.smb.lmCompatibility"
  35. , 3);
  36. private static readonly Random Random = new Random();
  37. private static LogStream _log = LogStream.GetInstance();
  38. private static readonly byte[] S8 = { unchecked(unchecked(0x4b)), unchecked(unchecked(0x47)), unchecked(unchecked(0x53)), unchecked(unchecked(0x21)), unchecked(unchecked(0x40)), unchecked(unchecked(0x23)), unchecked(unchecked(0x24)), unchecked(unchecked(0x25)) };
  39. // KGS!@#$%
  40. private static void E(byte[] key, byte[] data, byte[] e)
  41. {
  42. byte[] key7 = new byte[7];
  43. byte[] e8 = new byte[8];
  44. for (int i = 0; i < key.Length / 7; i++)
  45. {
  46. Array.Copy(key, i * 7, key7, 0, 7);
  47. DES des = new DES(key7);
  48. des.Encrypt(data, e8);
  49. Array.Copy(e8, 0, e, i * 8, 8);
  50. }
  51. }
  52. internal static string DefaultDomain;
  53. internal static string DefaultUsername;
  54. internal static string DefaultPassword;
  55. internal static readonly string Blank = string.Empty;
  56. public static readonly NtlmPasswordAuthentication Anonymous = new NtlmPasswordAuthentication
  57. (string.Empty, string.Empty, string.Empty);
  58. internal static void InitDefaults()
  59. {
  60. if (DefaultDomain != null)
  61. {
  62. return;
  63. }
  64. DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", "?");
  65. DefaultUsername = Config.GetProperty("jcifs.smb.client.username", "GUEST");
  66. DefaultPassword = Config.GetProperty("jcifs.smb.client.password", Blank);
  67. }
  68. /// <summary>Generate the ANSI DES hash for the password associated with these credentials.
  69. /// </summary>
  70. /// <remarks>Generate the ANSI DES hash for the password associated with these credentials.
  71. /// </remarks>
  72. public static byte[] GetPreNtlmResponse(string password, byte[] challenge)
  73. {
  74. byte[] p14 = new byte[14];
  75. byte[] p21 = new byte[21];
  76. byte[] p24 = new byte[24];
  77. byte[] passwordBytes;
  78. try
  79. {
  80. passwordBytes = Runtime.GetBytesForString(password.ToUpper(), SmbConstants.OemEncoding);
  81. }
  82. catch (UnsupportedEncodingException uee)
  83. {
  84. throw new RuntimeException("Try setting jcifs.encoding=US-ASCII", uee);
  85. }
  86. int passwordLength = passwordBytes.Length;
  87. // Only encrypt the first 14 bytes of the password for Pre 0.12 NT LM
  88. if (passwordLength > 14)
  89. {
  90. passwordLength = 14;
  91. }
  92. Array.Copy(passwordBytes, 0, p14, 0, passwordLength);
  93. E(p14, S8, p21);
  94. E(p21, challenge, p24);
  95. return p24;
  96. }
  97. /// <summary>Generate the Unicode MD4 hash for the password associated with these credentials.
  98. /// </summary>
  99. /// <remarks>Generate the Unicode MD4 hash for the password associated with these credentials.
  100. /// </remarks>
  101. public static byte[] GetNtlmResponse(string password, byte[] challenge)
  102. {
  103. byte[] uni = null;
  104. byte[] p21 = new byte[21];
  105. byte[] p24 = new byte[24];
  106. try
  107. {
  108. uni = Runtime.GetBytesForString(password, SmbConstants.UniEncoding);
  109. }
  110. catch (UnsupportedEncodingException uee)
  111. {
  112. if (_log.Level > 0)
  113. {
  114. Runtime.PrintStackTrace(uee, _log);
  115. }
  116. }
  117. Md4 md4 = new Md4();
  118. md4.Update(uni);
  119. try
  120. {
  121. md4.Digest(p21, 0, 16);
  122. }
  123. catch (Exception ex)
  124. {
  125. if (_log.Level > 0)
  126. {
  127. Runtime.PrintStackTrace(ex, _log);
  128. }
  129. }
  130. E(p21, challenge, p24);
  131. return p24;
  132. }
  133. /// <summary>Creates the LMv2 response for the supplied information.</summary>
  134. /// <remarks>Creates the LMv2 response for the supplied information.</remarks>
  135. /// <param name="domain">The domain in which the username exists.</param>
  136. /// <param name="user">The username.</param>
  137. /// <param name="password">The user's password.</param>
  138. /// <param name="challenge">The server challenge.</param>
  139. /// <param name="clientChallenge">The client challenge (nonce).</param>
  140. public static byte[] GetLMv2Response(string domain, string user, string password,
  141. byte[] challenge, byte[] clientChallenge)
  142. {
  143. try
  144. {
  145. byte[] hash = new byte[16];
  146. byte[] response = new byte[24];
  147. // The next 2-1/2 lines of this should be placed with nTOWFv1 in place of password
  148. Md4 md4 = new Md4();
  149. md4.Update(Runtime.GetBytesForString(password, SmbConstants.UniEncoding)
  150. );
  151. Hmact64 hmac = new Hmact64(md4.Digest());
  152. hmac.Update(Runtime.GetBytesForString(user.ToUpper(), SmbConstants.UniEncoding
  153. ));
  154. hmac.Update(Runtime.GetBytesForString(domain.ToUpper(), SmbConstants.UniEncoding
  155. ));
  156. hmac = new Hmact64(hmac.Digest());
  157. hmac.Update(challenge);
  158. hmac.Update(clientChallenge);
  159. hmac.Digest(response, 0, 16);
  160. Array.Copy(clientChallenge, 0, response, 16, 8);
  161. return response;
  162. }
  163. catch (Exception ex)
  164. {
  165. if (_log.Level > 0)
  166. {
  167. Runtime.PrintStackTrace(ex, _log);
  168. }
  169. return null;
  170. }
  171. }
  172. public static byte[] GetNtlm2Response(byte[] nTowFv1, byte[] serverChallenge, byte
  173. [] clientChallenge)
  174. {
  175. byte[] sessionHash = new byte[8];
  176. try
  177. {
  178. MessageDigest md5;
  179. md5 = MessageDigest.GetInstance("MD5");
  180. md5.Update(serverChallenge);
  181. md5.Update(clientChallenge, 0, 8);
  182. Array.Copy(md5.Digest(), 0, sessionHash, 0, 8);
  183. }
  184. catch (Exception gse)
  185. {
  186. if (_log.Level > 0)
  187. {
  188. Runtime.PrintStackTrace(gse, _log);
  189. }
  190. throw new RuntimeException("MD5", gse);
  191. }
  192. byte[] key = new byte[21];
  193. Array.Copy(nTowFv1, 0, key, 0, 16);
  194. byte[] ntResponse = new byte[24];
  195. E(key, sessionHash, ntResponse);
  196. return ntResponse;
  197. }
  198. public static byte[] NtowFv1(string password)
  199. {
  200. if (password == null)
  201. {
  202. throw new RuntimeException("Password parameter is required");
  203. }
  204. try
  205. {
  206. Md4 md4 = new Md4();
  207. md4.Update(Runtime.GetBytesForString(password, SmbConstants.UniEncoding)
  208. );
  209. return md4.Digest();
  210. }
  211. catch (UnsupportedEncodingException uee)
  212. {
  213. throw new RuntimeException(uee.Message);
  214. }
  215. }
  216. public static byte[] NtowFv2(string domain, string username, string password)
  217. {
  218. try
  219. {
  220. Md4 md4 = new Md4();
  221. md4.Update(Runtime.GetBytesForString(password, SmbConstants.UniEncoding)
  222. );
  223. Hmact64 hmac = new Hmact64(md4.Digest());
  224. hmac.Update(Runtime.GetBytesForString(username.ToUpper(), SmbConstants.UniEncoding
  225. ));
  226. hmac.Update(Runtime.GetBytesForString(domain, SmbConstants.UniEncoding));
  227. return hmac.Digest();
  228. }
  229. catch (UnsupportedEncodingException uee)
  230. {
  231. throw new RuntimeException(uee.Message);
  232. }
  233. }
  234. internal static byte[] ComputeResponse(byte[] responseKey, byte[] serverChallenge
  235. , byte[] clientData, int offset, int length)
  236. {
  237. Hmact64 hmac = new Hmact64(responseKey);
  238. hmac.Update(serverChallenge);
  239. hmac.Update(clientData, offset, length);
  240. byte[] mac = hmac.Digest();
  241. byte[] ret = new byte[mac.Length + clientData.Length];
  242. Array.Copy(mac, 0, ret, 0, mac.Length);
  243. Array.Copy(clientData, 0, ret, mac.Length, clientData.Length);
  244. return ret;
  245. }
  246. public static byte[] GetLMv2Response(byte[] responseKeyLm, byte[] serverChallenge
  247. , byte[] clientChallenge)
  248. {
  249. return ComputeResponse(responseKeyLm, serverChallenge
  250. , clientChallenge, 0, clientChallenge.Length);
  251. }
  252. public static byte[] GetNtlMv2Response(byte[] responseKeyNt, byte[] serverChallenge
  253. , byte[] clientChallenge, long nanos1601, byte[] targetInfo)
  254. {
  255. int targetInfoLength = targetInfo != null ? targetInfo.Length : 0;
  256. byte[] temp = new byte[28 + targetInfoLength + 4];
  257. Encdec.Enc_uint32le(unchecked(0x00000101), temp, 0);
  258. // Header
  259. Encdec.Enc_uint32le(unchecked(0x00000000), temp, 4);
  260. // Reserved
  261. Encdec.Enc_uint64le(nanos1601, temp, 8);
  262. Array.Copy(clientChallenge, 0, temp, 16, 8);
  263. Encdec.Enc_uint32le(unchecked(0x00000000), temp, 24);
  264. // Unknown
  265. if (targetInfo != null)
  266. {
  267. Array.Copy(targetInfo, 0, temp, 28, targetInfoLength);
  268. }
  269. Encdec.Enc_uint32le(unchecked(0x00000000), temp, 28 + targetInfoLength);
  270. // mystery bytes!
  271. return ComputeResponse(responseKeyNt, serverChallenge
  272. , temp, 0, temp.Length);
  273. }
  274. internal static readonly NtlmPasswordAuthentication Null = new NtlmPasswordAuthentication
  275. (string.Empty, string.Empty, string.Empty);
  276. internal static readonly NtlmPasswordAuthentication Guest = new NtlmPasswordAuthentication
  277. ("?", "GUEST", string.Empty);
  278. internal static readonly NtlmPasswordAuthentication Default = new NtlmPasswordAuthentication
  279. (null);
  280. internal string Domain;
  281. internal string Username;
  282. internal string Password;
  283. internal byte[] AnsiHash;
  284. internal byte[] UnicodeHash;
  285. internal bool HashesExternal;
  286. internal byte[] ClientChallenge;
  287. internal byte[] Challenge;
  288. /// <summary>
  289. /// Create an <tt>NtlmPasswordAuthentication</tt> object from the userinfo
  290. /// component of an SMB URL like "<tt>domain;user:pass</tt>".
  291. /// </summary>
  292. /// <remarks>
  293. /// Create an <tt>NtlmPasswordAuthentication</tt> object from the userinfo
  294. /// component of an SMB URL like "<tt>domain;user:pass</tt>". This constructor
  295. /// is used internally be jCIFS when parsing SMB URLs.
  296. /// </remarks>
  297. public NtlmPasswordAuthentication(string userInfo)
  298. {
  299. Domain = Username = Password = null;
  300. if (userInfo != null)
  301. {
  302. try
  303. {
  304. userInfo = Unescape(userInfo);
  305. }
  306. catch (UnsupportedEncodingException)
  307. {
  308. }
  309. int i;
  310. int u;
  311. int end;
  312. char c;
  313. end = userInfo.Length;
  314. for (i = 0, u = 0; i < end; i++)
  315. {
  316. c = userInfo[i];
  317. if (c == ';')
  318. {
  319. Domain = Runtime.Substring(userInfo, 0, i);
  320. u = i + 1;
  321. }
  322. else
  323. {
  324. if (c == ':')
  325. {
  326. Password = Runtime.Substring(userInfo, i + 1);
  327. break;
  328. }
  329. }
  330. }
  331. Username = Runtime.Substring(userInfo, u, i);
  332. }
  333. InitDefaults();
  334. if (Domain == null)
  335. {
  336. Domain = DefaultDomain;
  337. }
  338. if (Username == null)
  339. {
  340. Username = DefaultUsername;
  341. }
  342. if (Password == null)
  343. {
  344. Password = DefaultPassword;
  345. }
  346. }
  347. /// <summary>
  348. /// Create an <tt>NtlmPasswordAuthentication</tt> object from a
  349. /// domain, username, and password.
  350. /// </summary>
  351. /// <remarks>
  352. /// Create an <tt>NtlmPasswordAuthentication</tt> object from a
  353. /// domain, username, and password. Parameters that are <tt>null</tt>
  354. /// will be substituted with <tt>jcifs.smb.client.domain</tt>,
  355. /// <tt>jcifs.smb.client.username</tt>, <tt>jcifs.smb.client.password</tt>
  356. /// property values.
  357. /// </remarks>
  358. public NtlmPasswordAuthentication(string domain, string username, string password
  359. )
  360. {
  361. int ci;
  362. if (username != null)
  363. {
  364. ci = username.IndexOf('@');
  365. if (ci > 0)
  366. {
  367. domain = Runtime.Substring(username, ci + 1);
  368. username = Runtime.Substring(username, 0, ci);
  369. }
  370. else
  371. {
  372. ci = username.IndexOf('\\');
  373. if (ci > 0)
  374. {
  375. domain = Runtime.Substring(username, 0, ci);
  376. username = Runtime.Substring(username, ci + 1);
  377. }
  378. }
  379. }
  380. this.Domain = domain;
  381. this.Username = username;
  382. this.Password = password;
  383. InitDefaults();
  384. if (domain == null)
  385. {
  386. this.Domain = DefaultDomain;
  387. }
  388. if (username == null)
  389. {
  390. this.Username = DefaultUsername;
  391. }
  392. if (password == null)
  393. {
  394. this.Password = DefaultPassword;
  395. }
  396. }
  397. /// <summary>
  398. /// Create an <tt>NtlmPasswordAuthentication</tt> object with raw password
  399. /// hashes.
  400. /// </summary>
  401. /// <remarks>
  402. /// Create an <tt>NtlmPasswordAuthentication</tt> object with raw password
  403. /// hashes. This is used exclusively by the <tt>jcifs.http.NtlmSsp</tt>
  404. /// class which is in turn used by NTLM HTTP authentication functionality.
  405. /// </remarks>
  406. public NtlmPasswordAuthentication(string domain, string username, byte[] challenge
  407. , byte[] ansiHash, byte[] unicodeHash)
  408. {
  409. if (domain == null || username == null || ansiHash == null || unicodeHash == null)
  410. {
  411. throw new ArgumentException("External credentials cannot be null");
  412. }
  413. this.Domain = domain;
  414. this.Username = username;
  415. Password = null;
  416. this.Challenge = challenge;
  417. this.AnsiHash = ansiHash;
  418. this.UnicodeHash = unicodeHash;
  419. HashesExternal = true;
  420. }
  421. /// <summary>Returns the domain.</summary>
  422. /// <remarks>Returns the domain.</remarks>
  423. public string GetDomain()
  424. {
  425. return Domain;
  426. }
  427. /// <summary>Returns the username.</summary>
  428. /// <remarks>Returns the username.</remarks>
  429. public string GetUsername()
  430. {
  431. return Username;
  432. }
  433. /// <summary>
  434. /// Returns the password in plain text or <tt>null</tt> if the raw password
  435. /// hashes were used to construct this <tt>NtlmPasswordAuthentication</tt>
  436. /// object which will be the case when NTLM HTTP Authentication is
  437. /// used.
  438. /// </summary>
  439. /// <remarks>
  440. /// Returns the password in plain text or <tt>null</tt> if the raw password
  441. /// hashes were used to construct this <tt>NtlmPasswordAuthentication</tt>
  442. /// object which will be the case when NTLM HTTP Authentication is
  443. /// used. There is no way to retrieve a users password in plain text unless
  444. /// it is supplied by the user at runtime.
  445. /// </remarks>
  446. public string GetPassword()
  447. {
  448. return Password;
  449. }
  450. /// <summary>
  451. /// Return the domain and username in the format:
  452. /// <tt>domain\\username</tt>.
  453. /// </summary>
  454. /// <remarks>
  455. /// Return the domain and username in the format:
  456. /// <tt>domain\\username</tt>. This is equivalent to <tt>toString()</tt>.
  457. /// </remarks>
  458. public new string GetName()
  459. {
  460. bool d = Domain.Length > 0 && Domain.Equals("?") == false;
  461. return d ? Domain + "\\" + Username : Username;
  462. }
  463. /// <summary>Computes the 24 byte ANSI password hash given the 8 byte server challenge.
  464. /// </summary>
  465. /// <remarks>Computes the 24 byte ANSI password hash given the 8 byte server challenge.
  466. /// </remarks>
  467. public byte[] GetAnsiHash(byte[] challenge)
  468. {
  469. if (HashesExternal)
  470. {
  471. return AnsiHash;
  472. }
  473. switch (LmCompatibility)
  474. {
  475. case 0:
  476. case 1:
  477. {
  478. return GetPreNtlmResponse(Password, challenge);
  479. }
  480. case 2:
  481. {
  482. return GetNtlmResponse(Password, challenge);
  483. }
  484. case 3:
  485. case 4:
  486. case 5:
  487. {
  488. if (ClientChallenge == null)
  489. {
  490. ClientChallenge = new byte[8];
  491. Random.NextBytes(ClientChallenge);
  492. }
  493. return GetLMv2Response(Domain, Username, Password, challenge, ClientChallenge);
  494. }
  495. default:
  496. {
  497. return GetPreNtlmResponse(Password, challenge);
  498. }
  499. }
  500. }
  501. /// <summary>Computes the 24 byte Unicode password hash given the 8 byte server challenge.
  502. /// </summary>
  503. /// <remarks>Computes the 24 byte Unicode password hash given the 8 byte server challenge.
  504. /// </remarks>
  505. public byte[] GetUnicodeHash(byte[] challenge)
  506. {
  507. if (HashesExternal)
  508. {
  509. return UnicodeHash;
  510. }
  511. switch (LmCompatibility)
  512. {
  513. case 0:
  514. case 1:
  515. case 2:
  516. {
  517. return GetNtlmResponse(Password, challenge);
  518. }
  519. case 3:
  520. case 4:
  521. case 5:
  522. {
  523. return new byte[0];
  524. }
  525. default:
  526. {
  527. return GetNtlmResponse(Password, challenge);
  528. }
  529. }
  530. }
  531. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  532. public byte[] GetSigningKey(byte[] challenge)
  533. {
  534. switch (LmCompatibility)
  535. {
  536. case 0:
  537. case 1:
  538. case 2:
  539. {
  540. byte[] signingKey = new byte[40];
  541. GetUserSessionKey(challenge, signingKey, 0);
  542. Array.Copy(GetUnicodeHash(challenge), 0, signingKey, 16, 24);
  543. return signingKey;
  544. }
  545. case 3:
  546. case 4:
  547. case 5:
  548. {
  549. throw new SmbException("NTLMv2 requires extended security (jcifs.smb.client.useExtendedSecurity must be true if jcifs.smb.lmCompatibility >= 3)"
  550. );
  551. }
  552. }
  553. return null;
  554. }
  555. /// <summary>Returns the effective user session key.</summary>
  556. /// <remarks>Returns the effective user session key.</remarks>
  557. /// <param name="challenge">The server challenge.</param>
  558. /// <returns>
  559. /// A <code>byte[]</code> containing the effective user session key,
  560. /// used in SMB MAC signing and NTLMSSP signing and sealing.
  561. /// </returns>
  562. public byte[] GetUserSessionKey(byte[] challenge)
  563. {
  564. if (HashesExternal)
  565. {
  566. return null;
  567. }
  568. byte[] key = new byte[16];
  569. try
  570. {
  571. GetUserSessionKey(challenge, key, 0);
  572. }
  573. catch (Exception ex)
  574. {
  575. if (_log.Level > 0)
  576. {
  577. Runtime.PrintStackTrace(ex, _log);
  578. }
  579. }
  580. return key;
  581. }
  582. /// <summary>Calculates the effective user session key.</summary>
  583. /// <remarks>Calculates the effective user session key.</remarks>
  584. /// <param name="challenge">The server challenge.</param>
  585. /// <param name="dest">
  586. /// The destination array in which the user session key will be
  587. /// placed.
  588. /// </param>
  589. /// <param name="offset">
  590. /// The offset in the destination array at which the
  591. /// session key will start.
  592. /// </param>
  593. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  594. internal void GetUserSessionKey(byte[] challenge, byte[] dest, int offset)
  595. {
  596. if (HashesExternal)
  597. {
  598. return;
  599. }
  600. try
  601. {
  602. Md4 md4 = new Md4();
  603. md4.Update(Runtime.GetBytesForString(Password, SmbConstants.UniEncoding)
  604. );
  605. switch (LmCompatibility)
  606. {
  607. case 0:
  608. case 1:
  609. case 2:
  610. {
  611. md4.Update(md4.Digest());
  612. md4.Digest(dest, offset, 16);
  613. break;
  614. }
  615. case 3:
  616. case 4:
  617. case 5:
  618. {
  619. if (ClientChallenge == null)
  620. {
  621. ClientChallenge = new byte[8];
  622. Random.NextBytes(ClientChallenge);
  623. }
  624. Hmact64 hmac = new Hmact64(md4.Digest());
  625. hmac.Update(Runtime.GetBytesForString(Username.ToUpper(), SmbConstants.UniEncoding
  626. ));
  627. hmac.Update(Runtime.GetBytesForString(Domain.ToUpper(), SmbConstants.UniEncoding
  628. ));
  629. byte[] ntlmv2Hash = hmac.Digest();
  630. hmac = new Hmact64(ntlmv2Hash);
  631. hmac.Update(challenge);
  632. hmac.Update(ClientChallenge);
  633. Hmact64 userKey = new Hmact64(ntlmv2Hash);
  634. userKey.Update(hmac.Digest());
  635. userKey.Digest(dest, offset, 16);
  636. break;
  637. }
  638. default:
  639. {
  640. md4.Update(md4.Digest());
  641. md4.Digest(dest, offset, 16);
  642. break;
  643. }
  644. }
  645. }
  646. catch (Exception e)
  647. {
  648. throw new SmbException(string.Empty, e);
  649. }
  650. }
  651. /// <summary>
  652. /// Compares two <tt>NtlmPasswordAuthentication</tt> objects for
  653. /// equality.
  654. /// </summary>
  655. /// <remarks>
  656. /// Compares two <tt>NtlmPasswordAuthentication</tt> objects for
  657. /// equality. Two <tt>NtlmPasswordAuthentication</tt> objects are equal if
  658. /// their caseless domain and username fields are equal and either both hashes are external and they are equal or both internally supplied passwords are equal. If one <tt>NtlmPasswordAuthentication</tt> object has external hashes (meaning negotiated via NTLM HTTP Authentication) and the other does not they will not be equal. This is technically not correct however the server 8 byte challage would be required to compute and compare the password hashes but that it not available with this method.
  659. /// </remarks>
  660. public override bool Equals(object obj)
  661. {
  662. if (obj is NtlmPasswordAuthentication)
  663. {
  664. NtlmPasswordAuthentication ntlm = (NtlmPasswordAuthentication
  665. )obj;
  666. if (ntlm.Domain.ToUpper().Equals(Domain.ToUpper()) && ntlm.Username.ToUpper().Equals
  667. (Username.ToUpper()))
  668. {
  669. if (HashesExternal && ntlm.HashesExternal)
  670. {
  671. return Arrays.Equals(AnsiHash, ntlm.AnsiHash) && Arrays.Equals(UnicodeHash, ntlm.
  672. UnicodeHash);
  673. }
  674. if (!HashesExternal && Password.Equals(ntlm.Password))
  675. {
  676. return true;
  677. }
  678. }
  679. }
  680. return false;
  681. }
  682. /// <summary>Return the upcased username hash code.</summary>
  683. /// <remarks>Return the upcased username hash code.</remarks>
  684. public override int GetHashCode()
  685. {
  686. return GetName().ToUpper().GetHashCode();
  687. }
  688. /// <summary>
  689. /// Return the domain and username in the format:
  690. /// <tt>domain\\username</tt>.
  691. /// </summary>
  692. /// <remarks>
  693. /// Return the domain and username in the format:
  694. /// <tt>domain\\username</tt>. This is equivalent to <tt>getName()</tt>.
  695. /// </remarks>
  696. public override string ToString()
  697. {
  698. return GetName();
  699. }
  700. /// <exception cref="System.FormatException"></exception>
  701. /// <exception cref="UnsupportedEncodingException"></exception>
  702. internal static string Unescape(string str)
  703. {
  704. char ch;
  705. int i;
  706. int j;
  707. int state;
  708. int len;
  709. char[] @out;
  710. byte[] b = new byte[1];
  711. if (str == null)
  712. {
  713. return null;
  714. }
  715. len = str.Length;
  716. @out = new char[len];
  717. state = 0;
  718. for (i = j = 0; i < len; i++)
  719. {
  720. switch (state)
  721. {
  722. case 0:
  723. {
  724. ch = str[i];
  725. if (ch == '%')
  726. {
  727. state = 1;
  728. }
  729. else
  730. {
  731. @out[j++] = ch;
  732. }
  733. break;
  734. }
  735. case 1:
  736. {
  737. b[0] = unchecked((byte)(Convert.ToInt32(Runtime.Substring(str, i,
  738. i + 2), 16) & unchecked(0xFF)));
  739. @out[j++] = (Runtime.GetStringForBytes(b, 0, 1, "ASCII"))[0];
  740. i++;
  741. state = 0;
  742. break;
  743. }
  744. }
  745. }
  746. return new string(@out, 0, j);
  747. }
  748. }
  749. }