NTAuthentication.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Globalization;
  10. using System.Reflection;
  11. using System.Security.Cryptography;
  12. using System.Text;
  13. using Utilities;
  14. namespace SMBLibrary.Authentication
  15. {
  16. public class NTAuthentication
  17. {
  18. public static byte[] ComputeLMv1Response(byte[] challenge, string password)
  19. {
  20. byte[] hash = LMOWFv1(password);
  21. return DesLongEncrypt(hash, challenge);
  22. }
  23. public static byte[] ComputeNTLMv1Response(byte[] challenge, string password)
  24. {
  25. byte[] hash = NTOWFv1(password);
  26. return DesLongEncrypt(hash, challenge);
  27. }
  28. public static byte[] ComputeNTLMv1ExtendedSecurityResponse(byte[] serverChallenge, byte[] clientChallenge, string password)
  29. {
  30. byte[] passwordHash = NTOWFv1(password);
  31. byte[] challengeHash = MD5.Create().ComputeHash(ByteUtils.Concatenate(serverChallenge, clientChallenge));
  32. byte[] challengeHashShort = new byte[8];
  33. Array.Copy(challengeHash, 0, challengeHashShort, 0, 8);
  34. return DesLongEncrypt(passwordHash, challengeHashShort);
  35. }
  36. public static byte[] ComputeLMv2Response(byte[] serverChallenge, byte[] clientChallenge, string password, string user, string domain)
  37. {
  38. byte[] key = LMOWFv2(password, user, domain);
  39. byte[] bytes = ByteUtils.Concatenate(serverChallenge, clientChallenge);
  40. HMACMD5 hmac = new HMACMD5(key);
  41. byte[] hash = hmac.ComputeHash(bytes, 0, bytes.Length);
  42. return ByteUtils.Concatenate(hash, clientChallenge);
  43. }
  44. /// <summary>
  45. /// [MS-NLMP] https://msdn.microsoft.com/en-us/library/cc236700.aspx
  46. /// </summary>
  47. /// <param name="clientChallengeStructurePadded">ClientChallengeStructure with 4 zero bytes padding, a.k.a. temp</param>
  48. public static byte[] ComputeNTLMv2Proof(byte[] serverChallenge, byte[] clientChallengeStructurePadded, string password, string user, string domain)
  49. {
  50. byte[] key = NTOWFv2(password, user, domain);
  51. byte[] temp = clientChallengeStructurePadded;
  52. HMACMD5 hmac = new HMACMD5(key);
  53. byte[] _NTProof = hmac.ComputeHash(ByteUtils.Concatenate(serverChallenge, temp), 0, serverChallenge.Length + temp.Length);
  54. return _NTProof;
  55. }
  56. /// <summary>
  57. /// NTLMv2_CLIENT_CHALLENGE
  58. /// </summary>
  59. [Obsolete]
  60. public static byte[] GetNTLMv2ClientChallengeStructure(byte[] clientChallenge, byte responseVersion, byte responseVersionHigh, byte[] time, byte[] serverAVPair)
  61. {
  62. byte[] temp = new byte[28 + serverAVPair.Length];
  63. temp[0] = responseVersion;
  64. temp[1] = responseVersionHigh;
  65. Array.Copy(time, 0, temp, 8, 8);
  66. Array.Copy(clientChallenge, 0, temp, 16, 8);
  67. Array.Copy(serverAVPair, 0, temp, 28, serverAVPair.Length);
  68. return temp;
  69. }
  70. public static byte[] DesEncrypt(byte[] key, byte[] plainText)
  71. {
  72. return DesEncrypt(key, plainText, 0, plainText.Length);
  73. }
  74. public static byte[] DesEncrypt(byte[] key, byte[] plainText, int inputOffset, int inputCount)
  75. {
  76. ICryptoTransform encryptor = CreateWeakDesEncryptor(CipherMode.ECB, key, new byte[key.Length]);
  77. byte[] result = new byte[inputCount];
  78. encryptor.TransformBlock(plainText, inputOffset, inputCount, result, 0);
  79. return result;
  80. }
  81. public static ICryptoTransform CreateWeakDesEncryptor(CipherMode mode, byte[] rgbKey, byte[] rgbIV)
  82. {
  83. DES des = DES.Create();
  84. des.Mode = mode;
  85. DESCryptoServiceProvider sm = des as DESCryptoServiceProvider;
  86. MethodInfo mi = sm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
  87. object[] Par = { rgbKey, mode, rgbIV, sm.FeedbackSize, 0 };
  88. ICryptoTransform trans = mi.Invoke(sm, Par) as ICryptoTransform;
  89. return trans;
  90. }
  91. /// <summary>
  92. /// DESL()
  93. /// </summary>
  94. public static byte[] DesLongEncrypt(byte[] key, byte[] plainText)
  95. {
  96. if (key.Length != 16)
  97. {
  98. throw new ArgumentException("Invalid key length");
  99. }
  100. if (plainText.Length != 8)
  101. {
  102. throw new ArgumentException("Invalid plain-text length");
  103. }
  104. byte[] padded = new byte[21];
  105. Array.Copy(key, padded, key.Length);
  106. byte[] k1 = new byte[7];
  107. byte[] k2 = new byte[7];
  108. byte[] k3 = new byte[7];
  109. Array.Copy(padded, 0, k1, 0, 7);
  110. Array.Copy(padded, 7, k2, 0, 7);
  111. Array.Copy(padded, 14, k3, 0, 7);
  112. byte[] r1 = DesEncrypt(ExtendDESKey(k1), plainText);
  113. byte[] r2 = DesEncrypt(ExtendDESKey(k2), plainText);
  114. byte[] r3 = DesEncrypt(ExtendDESKey(k3), plainText);
  115. byte[] result = new byte[24];
  116. Array.Copy(r1, 0, result, 0, 8);
  117. Array.Copy(r2, 0, result, 8, 8);
  118. Array.Copy(r3, 0, result, 16, 8);
  119. return result;
  120. }
  121. public static Encoding GetOEMEncoding()
  122. {
  123. return Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
  124. }
  125. /// <summary>
  126. /// LM Hash
  127. /// </summary>
  128. public static byte[] LMOWFv1(string password)
  129. {
  130. byte[] plainText = ASCIIEncoding.ASCII.GetBytes("KGS!@#$%");
  131. byte[] passwordBytes = GetOEMEncoding().GetBytes(password.ToUpper());
  132. byte[] key = new byte[14];
  133. Array.Copy(passwordBytes, key, Math.Min(passwordBytes.Length, 14));
  134. byte[] k1 = new byte[7];
  135. byte[] k2 = new byte[7];
  136. Array.Copy(key, 0, k1, 0, 7);
  137. Array.Copy(key, 7, k2, 0, 7);
  138. byte[] part1 = DesEncrypt(ExtendDESKey(k1), plainText);
  139. byte[] part2 = DesEncrypt(ExtendDESKey(k2), plainText);
  140. return ByteUtils.Concatenate(part1, part2);
  141. }
  142. /// <summary>
  143. /// NTLM hash (NT hash)
  144. /// </summary>
  145. public static byte[] NTOWFv1(string password)
  146. {
  147. byte[] passwordBytes = UnicodeEncoding.Unicode.GetBytes(password);
  148. return new MD4().GetByteHashFromBytes(passwordBytes);
  149. }
  150. /// <summary>
  151. /// LMOWFv2 is identical to NTOWFv2
  152. /// </summary>
  153. public static byte[] LMOWFv2(string password, string user, string domain)
  154. {
  155. return NTOWFv2(password, user, domain);
  156. }
  157. public static byte[] NTOWFv2(string password, string user, string domain)
  158. {
  159. byte[] passwordBytes = UnicodeEncoding.Unicode.GetBytes(password);
  160. byte[] key = new MD4().GetByteHashFromBytes(passwordBytes);
  161. string text = user.ToUpper() + domain;
  162. byte[] bytes = UnicodeEncoding.Unicode.GetBytes(text);
  163. HMACMD5 hmac = new HMACMD5(key);
  164. return hmac.ComputeHash(bytes, 0, bytes.Length);
  165. }
  166. /// <summary>
  167. /// Extends a 7-byte key into an 8-byte key.
  168. /// Note: The DES key ostensibly consists of 64 bits, however, only 56 of these are actually used by the algorithm.
  169. /// Eight bits are used solely for checking parity, and are thereafter discarded
  170. /// </summary>
  171. private static byte[] ExtendDESKey(byte[] key)
  172. {
  173. byte[] result = new byte[8];
  174. int i;
  175. result[0] = (byte)((key[0] >> 1) & 0xff);
  176. result[1] = (byte)((((key[0] & 0x01) << 6) | (((key[1] & 0xff) >> 2) & 0xff)) & 0xff);
  177. result[2] = (byte)((((key[1] & 0x03) << 5) | (((key[2] & 0xff) >> 3) & 0xff)) & 0xff);
  178. result[3] = (byte)((((key[2] & 0x07) << 4) | (((key[3] & 0xff) >> 4) & 0xff)) & 0xff);
  179. result[4] = (byte)((((key[3] & 0x0F) << 3) | (((key[4] & 0xff) >> 5) & 0xff)) & 0xff);
  180. result[5] = (byte)((((key[4] & 0x1F) << 2) | (((key[5] & 0xff) >> 6) & 0xff)) & 0xff);
  181. result[6] = (byte)((((key[5] & 0x3F) << 1) | (((key[6] & 0xff) >> 7) & 0xff)) & 0xff);
  182. result[7] = (byte)(key[6] & 0x7F);
  183. for (i = 0; i < 8; i++)
  184. {
  185. result[i] = (byte)(result[i] << 1);
  186. }
  187. return result;
  188. }
  189. }
  190. }