SigningDigest.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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>To filter 0 len updates and for debugging</summary>
  23. public class SigningDigest
  24. {
  25. internal static LogStream Log = LogStream.GetInstance();
  26. private MessageDigest _digest;
  27. private byte[] _macSigningKey;
  28. private bool _bypass;
  29. private int _updates;
  30. private int _signSequence;
  31. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  32. public SigningDigest(byte[] macSigningKey, bool bypass)
  33. {
  34. try
  35. {
  36. _digest = MessageDigest.GetInstance("MD5");
  37. }
  38. catch (NoSuchAlgorithmException ex)
  39. {
  40. if (Log.Level > 0)
  41. {
  42. Runtime.PrintStackTrace(ex, Log);
  43. }
  44. throw new SmbException("MD5", ex);
  45. }
  46. this._macSigningKey = macSigningKey;
  47. this._bypass = bypass;
  48. _updates = 0;
  49. _signSequence = 0;
  50. if (Log.Level >= 5)
  51. {
  52. Log.WriteLine("macSigningKey:");
  53. Hexdump.ToHexdump(Log, macSigningKey, 0, macSigningKey.Length);
  54. }
  55. }
  56. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  57. public SigningDigest(SmbTransport transport, NtlmPasswordAuthentication auth)
  58. {
  59. try
  60. {
  61. _digest = MessageDigest.GetInstance("MD5");
  62. }
  63. catch (NoSuchAlgorithmException ex)
  64. {
  65. if (Log.Level > 0)
  66. {
  67. Runtime.PrintStackTrace(ex, Log);
  68. }
  69. throw new SmbException("MD5", ex);
  70. }
  71. try
  72. {
  73. switch (SmbConstants.LmCompatibility)
  74. {
  75. case 0:
  76. case 1:
  77. case 2:
  78. {
  79. _macSigningKey = new byte[40];
  80. auth.GetUserSessionKey(transport.Server.EncryptionKey,
  81. _macSigningKey,
  82. 0);
  83. Array.Copy(auth.GetUnicodeHash(transport.Server.EncryptionKey),
  84. 0,
  85. _macSigningKey,
  86. 16,
  87. 24);
  88. break;
  89. }
  90. case 3:
  91. case 4:
  92. case 5:
  93. {
  94. _macSigningKey = new byte[16];
  95. auth.GetUserSessionKey(transport.Server.EncryptionKey, _macSigningKey, 0);
  96. break;
  97. }
  98. default:
  99. {
  100. _macSigningKey = new byte[40];
  101. auth.GetUserSessionKey(transport.Server.EncryptionKey, _macSigningKey, 0);
  102. Array.Copy(auth.GetUnicodeHash(transport.Server.EncryptionKey),
  103. 0,
  104. _macSigningKey,
  105. 16,
  106. 24);
  107. break;
  108. }
  109. }
  110. }
  111. catch (Exception ex)
  112. {
  113. throw new SmbException(string.Empty, ex);
  114. }
  115. if (Log.Level >= 5)
  116. {
  117. Log.WriteLine("LM_COMPATIBILITY=" + SmbConstants.LmCompatibility);
  118. Hexdump.ToHexdump(Log, _macSigningKey, 0, _macSigningKey.Length);
  119. }
  120. }
  121. public virtual void Update(byte[] input, int offset, int len)
  122. {
  123. if (Log.Level >= 5)
  124. {
  125. Log.WriteLine("update: " + _updates + " " + offset + ":" + len);
  126. Hexdump.ToHexdump(Log, input, offset, Math.Min(len, 256));
  127. Log.Flush();
  128. }
  129. if (len == 0)
  130. {
  131. return;
  132. }
  133. _digest.Update(input, offset, len);
  134. _updates++;
  135. }
  136. public virtual byte[] Digest()
  137. {
  138. byte[] b;
  139. b = _digest.Digest();
  140. if (Log.Level >= 5)
  141. {
  142. Log.WriteLine("digest: ");
  143. Hexdump.ToHexdump(Log, b, 0, b.Length);
  144. Log.Flush();
  145. }
  146. _updates = 0;
  147. return b;
  148. }
  149. /// <summary>Performs MAC signing of the SMB.</summary>
  150. /// <remarks>
  151. /// Performs MAC signing of the SMB. This is done as follows.
  152. /// The signature field of the SMB is overwritted with the sequence number;
  153. /// The MD5 digest of the MAC signing key + the entire SMB is taken;
  154. /// The first 8 bytes of this are placed in the signature field.
  155. /// </remarks>
  156. /// <param name="data">The data.</param>
  157. /// <param name="offset">The starting offset at which the SMB header begins.</param>
  158. /// <param name="length">The length of the SMB data starting at offset.</param>
  159. internal virtual void Sign(byte[] data,
  160. int offset,
  161. int length,
  162. ServerMessageBlock request,
  163. ServerMessageBlock response)
  164. {
  165. request.SignSeq = _signSequence;
  166. if (response != null)
  167. {
  168. response.SignSeq = _signSequence + 1;
  169. response.VerifyFailed = false;
  170. }
  171. try
  172. {
  173. Update(_macSigningKey, 0, _macSigningKey.Length);
  174. int index = offset + SmbConstants.SignatureOffset;
  175. for (int i = 0; i < 8; i++)
  176. {
  177. data[index + i] = 0;
  178. }
  179. ServerMessageBlock.WriteInt4(_signSequence, data, index);
  180. Update(data, offset, length);
  181. Array.Copy(Digest(), 0, data, index, 8);
  182. if (_bypass)
  183. {
  184. _bypass = false;
  185. Array.Copy(Runtime.GetBytesForString("BSRSPYL "),
  186. 0,
  187. data,
  188. index,
  189. 8);
  190. }
  191. }
  192. catch (Exception ex)
  193. {
  194. if (Log.Level > 0)
  195. {
  196. Runtime.PrintStackTrace(ex, Log);
  197. }
  198. }
  199. finally
  200. {
  201. _signSequence += 2;
  202. }
  203. }
  204. /// <summary>Performs MAC signature verification.</summary>
  205. /// <remarks>
  206. /// Performs MAC signature verification. This calculates the signature
  207. /// of the SMB and compares it to the signature field on the SMB itself.
  208. /// </remarks>
  209. /// <param name="data">The data.</param>
  210. /// <param name="offset">The starting offset at which the SMB header begins.</param>
  211. /// <param name="length">The length of the SMB data starting at offset.</param>
  212. internal virtual bool Verify(byte[] data, int offset, ServerMessageBlock response)
  213. {
  214. Update(_macSigningKey, 0, _macSigningKey.Length);
  215. int index = offset;
  216. Update(data, index, SmbConstants.SignatureOffset);
  217. index += SmbConstants.SignatureOffset;
  218. byte[] sequence = new byte[8];
  219. ServerMessageBlock.WriteInt4(response.SignSeq, sequence, 0);
  220. Update(sequence, 0, sequence.Length);
  221. index += 8;
  222. if (response.Command == ServerMessageBlock.SmbComReadAndx)
  223. {
  224. SmbComReadAndXResponse raxr = (SmbComReadAndXResponse)response;
  225. int length = response.Length - raxr.DataLength;
  226. Update(data, index, length - SmbConstants.SignatureOffset - 8);
  227. Update(raxr.B, raxr.Off, raxr.DataLength);
  228. }
  229. else
  230. {
  231. Update(data, index, response.Length - SmbConstants.SignatureOffset - 8);
  232. }
  233. byte[] signature = Digest();
  234. for (int i = 0; i < 8; i++)
  235. {
  236. if (signature[i] != data[offset + SmbConstants.SignatureOffset + i])
  237. {
  238. if (Log.Level >= 2)
  239. {
  240. Log.WriteLine("signature verification failure");
  241. Hexdump.ToHexdump(Log, signature, 0, 8);
  242. Hexdump.ToHexdump(Log, data, offset + SmbConstants.SignatureOffset, 8);
  243. }
  244. return response.VerifyFailed = true;
  245. }
  246. }
  247. return response.VerifyFailed = false;
  248. }
  249. public override string ToString()
  250. {
  251. return "LM_COMPATIBILITY=" + SmbConstants.LmCompatibility
  252. + " MacSigningKey=" + Hexdump.ToHexString(_macSigningKey,
  253. 0,
  254. _macSigningKey.Length);
  255. }
  256. }
  257. }