MD4.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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.Sharpen;
  19. namespace SharpCifs.Util
  20. {
  21. /// <summary>Implements the MD4 message digest algorithm in Java.</summary>
  22. /// <remarks>
  23. /// Implements the MD4 message digest algorithm in Java.
  24. /// <p>
  25. /// <b>References:</b>
  26. /// <ol>
  27. /// <li> Ronald L. Rivest,
  28. /// "<a href="http://www.roxen.com/rfc/rfc1320.html">
  29. /// The MD4 Message-Digest Algorithm</a>",
  30. /// IETF RFC-1320 (informational).
  31. /// </ol>
  32. /// <p><b>$Revision: 1.2 $</b>
  33. /// </remarks>
  34. /// <author>Raif S. Naffah</author>
  35. public class Md4 : MessageDigest
  36. {
  37. /// <summary>The size in bytes of the input block to the tranformation algorithm.</summary>
  38. /// <remarks>The size in bytes of the input block to the tranformation algorithm.</remarks>
  39. private const int BlockLength = 64;
  40. /// <summary>4 32-bit words (interim result)</summary>
  41. private int[] _context = new int[4];
  42. /// <summary>Number of bytes processed so far mod.</summary>
  43. /// <remarks>Number of bytes processed so far mod. 2 power of 64.</remarks>
  44. private long _count;
  45. /// <summary>512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.</summary>
  46. /// <remarks>512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.</remarks>
  47. private byte[] _buffer = new byte[BlockLength];
  48. /// <summary>512 bits work buffer = 16 x 32-bit words</summary>
  49. private int[] _x = new int[16];
  50. public Md4()
  51. {
  52. // This file is currently unlocked (change this line if you lock the file)
  53. //
  54. // $Log: MD4.java,v $
  55. // Revision 1.2 1998/01/05 03:41:19 iang
  56. // Added references only.
  57. //
  58. // Revision 1.1.1.1 1997/11/03 22:36:56 hopwood
  59. // + Imported to CVS (tagged as 'start').
  60. //
  61. // Revision 0.1.0.0 1997/07/14 R. Naffah
  62. // + original version
  63. //
  64. // $Endlog$
  65. // MD4 specific object variables
  66. //...........................................................................
  67. // = 512 / 8;
  68. // Constructors
  69. //...........................................................................
  70. EngineReset();
  71. }
  72. /// <summary>This constructor is here to implement cloneability of this class.</summary>
  73. /// <remarks>This constructor is here to implement cloneability of this class.</remarks>
  74. private Md4(Md4 md) : this()
  75. {
  76. _context = (int[])md._context.Clone();
  77. _buffer = (byte[])md._buffer.Clone();
  78. _count = md._count;
  79. }
  80. // Cloneable method implementation
  81. //...........................................................................
  82. /// <summary>Returns a copy of this MD object.</summary>
  83. /// <remarks>Returns a copy of this MD object.</remarks>
  84. public object Clone()
  85. {
  86. return new Md4(this);
  87. }
  88. // JCE methods
  89. //...........................................................................
  90. /// <summary>
  91. /// Resets this object disregarding any temporary data present at the
  92. /// time of the invocation of this call.
  93. /// </summary>
  94. /// <remarks>
  95. /// Resets this object disregarding any temporary data present at the
  96. /// time of the invocation of this call.
  97. /// </remarks>
  98. protected void EngineReset()
  99. {
  100. // initial values of MD4 i.e. A, B, C, D
  101. // as per rfc-1320; they are low-order byte first
  102. _context[0] = unchecked(0x67452301);
  103. _context[1] = unchecked((int)(0xEFCDAB89));
  104. _context[2] = unchecked((int)(0x98BADCFE));
  105. _context[3] = unchecked(0x10325476);
  106. _count = 0L;
  107. for (int i = 0; i < BlockLength; i++)
  108. {
  109. _buffer[i] = 0;
  110. }
  111. }
  112. /// <summary>Continues an MD4 message digest using the input byte.</summary>
  113. /// <remarks>Continues an MD4 message digest using the input byte.</remarks>
  114. protected void EngineUpdate(byte b)
  115. {
  116. // compute number of bytes still unhashed; ie. present in buffer
  117. int i = (int)(_count % BlockLength);
  118. _count++;
  119. // update number of bytes
  120. _buffer[i] = b;
  121. if (i == BlockLength - 1)
  122. {
  123. Transform(_buffer, 0);
  124. }
  125. }
  126. /// <summary>MD4 block update operation.</summary>
  127. /// <remarks>
  128. /// MD4 block update operation.
  129. /// <p>
  130. /// Continues an MD4 message digest operation, by filling the buffer,
  131. /// transform(ing) data in 512-bit message block(s), updating the variables
  132. /// context and count, and leaving (buffering) the remaining bytes in buffer
  133. /// for the next update or finish.
  134. /// </remarks>
  135. /// <param name="input">input block</param>
  136. /// <param name="offset">start of meaningful bytes in input</param>
  137. /// <param name="len">count of bytes in input block to consider</param>
  138. protected void EngineUpdate(byte[] input, int offset, int len)
  139. {
  140. // make sure we don't exceed input's allocated size/length
  141. if (offset < 0 || len < 0 || (long)offset + len > input.Length)
  142. {
  143. throw new IndexOutOfRangeException();
  144. }
  145. // compute number of bytes still unhashed; ie. present in buffer
  146. int bufferNdx = (int)(_count % BlockLength);
  147. _count += len;
  148. // update number of bytes
  149. int partLen = BlockLength - bufferNdx;
  150. int i = 0;
  151. if (len >= partLen)
  152. {
  153. Array.Copy(input, offset, _buffer, bufferNdx, partLen);
  154. Transform(_buffer, 0);
  155. for (i = partLen; i + BlockLength - 1 < len; i += BlockLength)
  156. {
  157. Transform(input, offset + i);
  158. }
  159. bufferNdx = 0;
  160. }
  161. // buffer remaining input
  162. if (i < len)
  163. {
  164. Array.Copy(input, offset + i, _buffer, bufferNdx, len - i);
  165. }
  166. }
  167. /// <summary>
  168. /// Completes the hash computation by performing final operations such
  169. /// as padding.
  170. /// </summary>
  171. /// <remarks>
  172. /// Completes the hash computation by performing final operations such
  173. /// as padding. At the return of this engineDigest, the MD engine is
  174. /// reset.
  175. /// </remarks>
  176. /// <returns>the array of bytes for the resulting hash value.</returns>
  177. protected byte[] EngineDigest()
  178. {
  179. // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
  180. int bufferNdx = (int)(_count % BlockLength);
  181. int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
  182. // padding is alwas binary 1 followed by binary 0s
  183. byte[] tail = new byte[padLen + 8];
  184. tail[0] = unchecked(unchecked(0x80));
  185. // append length before final transform:
  186. // save number of bits, casting the long to an array of 8 bytes
  187. // save low-order byte first.
  188. for (int i = 0; i < 8; i++)
  189. {
  190. tail[padLen + i] = unchecked((byte)((long)(((ulong)(_count * 8)) >> (8 * i))));
  191. }
  192. EngineUpdate(tail, 0, tail.Length);
  193. byte[] result = new byte[16];
  194. // cast this MD4's context (array of 4 ints) into an array of 16 bytes.
  195. for (int i1 = 0; i1 < 4; i1++)
  196. {
  197. for (int j = 0; j < 4; j++)
  198. {
  199. result[i1 * 4 + j] = unchecked((byte)((int)(((uint)_context[i1]) >> (8 * j))));
  200. }
  201. }
  202. // reset the engine
  203. EngineReset();
  204. return result;
  205. }
  206. // own methods
  207. //...........................................................................
  208. /// <summary>MD4 basic transformation.</summary>
  209. /// <remarks>
  210. /// MD4 basic transformation.
  211. /// <p>
  212. /// Transforms context based on 512 bits from input block starting
  213. /// from the offset'th byte.
  214. /// </remarks>
  215. /// <param name="block">input sub-array.</param>
  216. /// <param name="offset">starting position of sub-array.</param>
  217. private void Transform(byte[] block, int offset)
  218. {
  219. // encodes 64 bytes from input block into an array of 16 32-bit
  220. // entities. Use A as a temp var.
  221. for (int i = 0; i < 16; i++)
  222. {
  223. _x[i] = (block[offset++] & unchecked(0xFF)) | (block[offset++] & unchecked(
  224. 0xFF)) << 8 | (block[offset++] & unchecked(0xFF)) << 16 | (block[offset
  225. ++] & unchecked(0xFF)) << 24;
  226. }
  227. int a = _context[0];
  228. int b = _context[1];
  229. int c = _context[2];
  230. int d = _context[3];
  231. a = Ff(a, b, c, d, _x[0], 3);
  232. d = Ff(d, a, b, c, _x[1], 7);
  233. c = Ff(c, d, a, b, _x[2], 11);
  234. b = Ff(b, c, d, a, _x[3], 19);
  235. a = Ff(a, b, c, d, _x[4], 3);
  236. d = Ff(d, a, b, c, _x[5], 7);
  237. c = Ff(c, d, a, b, _x[6], 11);
  238. b = Ff(b, c, d, a, _x[7], 19);
  239. a = Ff(a, b, c, d, _x[8], 3);
  240. d = Ff(d, a, b, c, _x[9], 7);
  241. c = Ff(c, d, a, b, _x[10], 11);
  242. b = Ff(b, c, d, a, _x[11], 19);
  243. a = Ff(a, b, c, d, _x[12], 3);
  244. d = Ff(d, a, b, c, _x[13], 7);
  245. c = Ff(c, d, a, b, _x[14], 11);
  246. b = Ff(b, c, d, a, _x[15], 19);
  247. a = Gg(a, b, c, d, _x[0], 3);
  248. d = Gg(d, a, b, c, _x[4], 5);
  249. c = Gg(c, d, a, b, _x[8], 9);
  250. b = Gg(b, c, d, a, _x[12], 13);
  251. a = Gg(a, b, c, d, _x[1], 3);
  252. d = Gg(d, a, b, c, _x[5], 5);
  253. c = Gg(c, d, a, b, _x[9], 9);
  254. b = Gg(b, c, d, a, _x[13], 13);
  255. a = Gg(a, b, c, d, _x[2], 3);
  256. d = Gg(d, a, b, c, _x[6], 5);
  257. c = Gg(c, d, a, b, _x[10], 9);
  258. b = Gg(b, c, d, a, _x[14], 13);
  259. a = Gg(a, b, c, d, _x[3], 3);
  260. d = Gg(d, a, b, c, _x[7], 5);
  261. c = Gg(c, d, a, b, _x[11], 9);
  262. b = Gg(b, c, d, a, _x[15], 13);
  263. a = Hh(a, b, c, d, _x[0], 3);
  264. d = Hh(d, a, b, c, _x[8], 9);
  265. c = Hh(c, d, a, b, _x[4], 11);
  266. b = Hh(b, c, d, a, _x[12], 15);
  267. a = Hh(a, b, c, d, _x[2], 3);
  268. d = Hh(d, a, b, c, _x[10], 9);
  269. c = Hh(c, d, a, b, _x[6], 11);
  270. b = Hh(b, c, d, a, _x[14], 15);
  271. a = Hh(a, b, c, d, _x[1], 3);
  272. d = Hh(d, a, b, c, _x[9], 9);
  273. c = Hh(c, d, a, b, _x[5], 11);
  274. b = Hh(b, c, d, a, _x[13], 15);
  275. a = Hh(a, b, c, d, _x[3], 3);
  276. d = Hh(d, a, b, c, _x[11], 9);
  277. c = Hh(c, d, a, b, _x[7], 11);
  278. b = Hh(b, c, d, a, _x[15], 15);
  279. _context[0] += a;
  280. _context[1] += b;
  281. _context[2] += c;
  282. _context[3] += d;
  283. }
  284. // The basic MD4 atomic functions.
  285. private int Ff(int a, int b, int c, int d, int x, int s)
  286. {
  287. int t = a + ((b & c) | (~b & d)) + x;
  288. return t << s | (int)(((uint)t) >> (32 - s));
  289. }
  290. private int Gg(int a, int b, int c, int d, int x, int s)
  291. {
  292. int t = a + ((b & (c | d)) | (c & d)) + x + unchecked(0x5A827999);
  293. return t << s | (int)(((uint)t) >> (32 - s));
  294. }
  295. private int Hh(int a, int b, int c, int d, int x, int s)
  296. {
  297. int t = a + (b ^ c ^ d) + x + unchecked(0x6ED9EBA1);
  298. return t << s | (int)(((uint)t) >> (32 - s));
  299. }
  300. public override byte[] Digest()
  301. {
  302. return EngineDigest();
  303. }
  304. public override int GetDigestLength()
  305. {
  306. return EngineDigest().Length;
  307. }
  308. public override void Reset()
  309. {
  310. EngineReset();
  311. }
  312. public override void Update(byte[] b)
  313. {
  314. EngineUpdate(b, 0, b.Length);
  315. }
  316. public override void Update(byte b)
  317. {
  318. EngineUpdate(b);
  319. }
  320. public override void Update(byte[] b, int offset, int len)
  321. {
  322. EngineUpdate(b, offset, len);
  323. }
  324. }
  325. }