MD5CryptoServiceProvider.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //
  2. // System.Security.Cryptography MD5CryptoServiceProvider Class implementation
  3. //
  4. // Authors:
  5. // Matthew S. Ford ([email protected])
  6. //
  7. // Copyright 2001 by Matthew S. Ford.
  8. //
  9. using System.Security.Cryptography;
  10. namespace System.Security.Cryptography {
  11. /// <summary>
  12. /// C# implementation of the MD5 cryptographic hash function.
  13. /// </summary>
  14. public class MD5CryptoServiceProvider : MD5 {
  15. private const int BLOCK_SIZE_BYTES = 64;
  16. private const int HASH_SIZE_BYTES = 16;
  17. private const int HASH_SIZE_BITS = 128;
  18. protected uint[] _H;
  19. protected uint count;
  20. private byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
  21. private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
  22. /// <summary>
  23. /// Creates a new MD5CryptoServiceProvider.
  24. /// </summary>
  25. public MD5CryptoServiceProvider () {
  26. _H = new uint[4];
  27. HashSizeValue = HASH_SIZE_BITS;
  28. _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
  29. Initialize();
  30. }
  31. /// <summary>
  32. /// Drives the hashing function.
  33. /// </summary>
  34. /// <param name="rgb">Byte array containing the data to hash.</param>
  35. /// <param name="start">Where in the input buffer to start.</param>
  36. /// <param name="size">Size in bytes of the data in the buffer to hash.</param>
  37. protected override void HashCore (byte[] rgb, int start, int size) {
  38. int i;
  39. State = 1;
  40. if (_ProcessingBufferCount != 0) {
  41. if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount)) {
  42. System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
  43. _ProcessingBufferCount += size;
  44. return;
  45. }
  46. else {
  47. i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
  48. System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
  49. ProcessBlock (_ProcessingBuffer, 0);
  50. _ProcessingBufferCount = 0;
  51. start += i;
  52. size -= i;
  53. }
  54. }
  55. for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES) {
  56. ProcessBlock (rgb, start+i);
  57. }
  58. if (size%BLOCK_SIZE_BYTES != 0) {
  59. System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
  60. _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
  61. }
  62. }
  63. /// <summary>
  64. /// This finalizes the hash. Takes the data from the chaining variables and returns it.
  65. /// </summary>
  66. protected override byte[] HashFinal () {
  67. byte[] hash = new byte[16];
  68. int i, j;
  69. ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
  70. for (i=0; i<4; i++) {
  71. for (j=0; j<4; j++) {
  72. hash[i*4+j] = (byte)(_H[i] >> j*8);
  73. }
  74. }
  75. return hash;
  76. }
  77. /// <summary>
  78. /// Resets the class after use. Called automatically after hashing is done.
  79. /// </summary>
  80. public override void Initialize () {
  81. count = 0;
  82. _ProcessingBufferCount = 0;
  83. _H[0] = 0x67452301;
  84. _H[1] = 0xefcdab89;
  85. _H[2] = 0x98badcfe;
  86. _H[3] = 0x10325476;
  87. }
  88. /// <summary>
  89. /// This is the meat of the hash function. It is what processes each block one at a time.
  90. /// </summary>
  91. /// <param name="inputBuffer">Byte array to process data from.</param>
  92. /// <param name="inputOffset">Where in the byte array to start processing.</param>
  93. private void ProcessBlock(byte[] inputBuffer, int inputOffset) {
  94. uint[] buff = new uint[16];
  95. uint a, b, c, d;
  96. int i;
  97. count += BLOCK_SIZE_BYTES;
  98. for (i=0; i<16; i++) {
  99. buff[i] = (uint)(inputBuffer[inputOffset+4*i])
  100. | (((uint)(inputBuffer[inputOffset+4*i+1])) << 8)
  101. | (((uint)(inputBuffer[inputOffset+4*i+2])) << 16)
  102. | (((uint)(inputBuffer[inputOffset+4*i+3])) << 24);
  103. }
  104. a = _H[0];
  105. b = _H[1];
  106. c = _H[2];
  107. d = _H[3];
  108. // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
  109. // Possibly roll up if this changes.
  110. // ---- Round 1 --------
  111. a += (((c ^ d) & b) ^ d) + (uint) Constants.C0 + buff [0];
  112. a = (a << 7) | (a >> 25);
  113. a += b;
  114. d += (((b ^ c) & a) ^ c) + (uint) Constants.C1 + buff [1];
  115. d = (d << 12) | (d >> 20);
  116. d += a;
  117. c += (((a ^ b) & d) ^ b) + (uint) Constants.C2 + buff [2];
  118. c = (c << 17) | (c >> 15);
  119. c += d;
  120. b += (((d ^ a) & c) ^ a) + (uint) Constants.C3 + buff [3];
  121. b = (b << 22) | (b >> 10);
  122. b += c;
  123. a += (((c ^ d) & b) ^ d) + (uint) Constants.C4 + buff [4];
  124. a = (a << 7) | (a >> 25);
  125. a += b;
  126. d += (((b ^ c) & a) ^ c) + (uint) Constants.C5 + buff [5];
  127. d = (d << 12) | (d >> 20);
  128. d += a;
  129. c += (((a ^ b) & d) ^ b) + (uint) Constants.C6 + buff [6];
  130. c = (c << 17) | (c >> 15);
  131. c += d;
  132. b += (((d ^ a) & c) ^ a) + (uint) Constants.C7 + buff [7];
  133. b = (b << 22) | (b >> 10);
  134. b += c;
  135. a += (((c ^ d) & b) ^ d) + (uint) Constants.C8 + buff [8];
  136. a = (a << 7) | (a >> 25);
  137. a += b;
  138. d += (((b ^ c) & a) ^ c) + (uint) Constants.C9 + buff [9];
  139. d = (d << 12) | (d >> 20);
  140. d += a;
  141. c += (((a ^ b) & d) ^ b) + (uint) Constants.C10 + buff [10];
  142. c = (c << 17) | (c >> 15);
  143. c += d;
  144. b += (((d ^ a) & c) ^ a) + (uint) Constants.C11 + buff [11];
  145. b = (b << 22) | (b >> 10);
  146. b += c;
  147. a += (((c ^ d) & b) ^ d) + (uint) Constants.C12 + buff [12];
  148. a = (a << 7) | (a >> 25);
  149. a += b;
  150. d += (((b ^ c) & a) ^ c) + (uint) Constants.C13 + buff [13];
  151. d = (d << 12) | (d >> 20);
  152. d += a;
  153. c += (((a ^ b) & d) ^ b) + (uint) Constants.C14 + buff [14];
  154. c = (c << 17) | (c >> 15);
  155. c += d;
  156. b += (((d ^ a) & c) ^ a) + (uint) Constants.C15 + buff [15];
  157. b = (b << 22) | (b >> 10);
  158. b += c;
  159. // ---- Round 2 --------
  160. a += (((b ^ c) & d) ^ c) + (uint) Constants.C16 + buff [1];
  161. a = (a << 5) | (a >> 27);
  162. a += b;
  163. d += (((a ^ b) & c) ^ b) + (uint) Constants.C17 + buff [6];
  164. d = (d << 9) | (d >> 23);
  165. d += a;
  166. c += (((d ^ a) & b) ^ a) + (uint) Constants.C18 + buff [11];
  167. c = (c << 14) | (c >> 18);
  168. c += d;
  169. b += (((c ^ d) & a) ^ d) + (uint) Constants.C19 + buff [0];
  170. b = (b << 20) | (b >> 12);
  171. b += c;
  172. a += (((b ^ c) & d) ^ c) + (uint) Constants.C20 + buff [5];
  173. a = (a << 5) | (a >> 27);
  174. a += b;
  175. d += (((a ^ b) & c) ^ b) + (uint) Constants.C21 + buff [10];
  176. d = (d << 9) | (d >> 23);
  177. d += a;
  178. c += (((d ^ a) & b) ^ a) + (uint) Constants.C22 + buff [15];
  179. c = (c << 14) | (c >> 18);
  180. c += d;
  181. b += (((c ^ d) & a) ^ d) + (uint) Constants.C23 + buff [4];
  182. b = (b << 20) | (b >> 12);
  183. b += c;
  184. a += (((b ^ c) & d) ^ c) + (uint) Constants.C24 + buff [9];
  185. a = (a << 5) | (a >> 27);
  186. a += b;
  187. d += (((a ^ b) & c) ^ b) + (uint) Constants.C25 + buff [14];
  188. d = (d << 9) | (d >> 23);
  189. d += a;
  190. c += (((d ^ a) & b) ^ a) + (uint) Constants.C26 + buff [3];
  191. c = (c << 14) | (c >> 18);
  192. c += d;
  193. b += (((c ^ d) & a) ^ d) + (uint) Constants.C27 + buff [8];
  194. b = (b << 20) | (b >> 12);
  195. b += c;
  196. a += (((b ^ c) & d) ^ c) + (uint) Constants.C28 + buff [13];
  197. a = (a << 5) | (a >> 27);
  198. a += b;
  199. d += (((a ^ b) & c) ^ b) + (uint) Constants.C29 + buff [2];
  200. d = (d << 9) | (d >> 23);
  201. d += a;
  202. c += (((d ^ a) & b) ^ a) + (uint) Constants.C30 + buff [7];
  203. c = (c << 14) | (c >> 18);
  204. c += d;
  205. b += (((c ^ d) & a) ^ d) + (uint) Constants.C31 + buff [12];
  206. b = (b << 20) | (b >> 12);
  207. b += c;
  208. // ---- Round 3 --------
  209. a += (b ^ c ^ d) + (uint) Constants.C32 + buff [5];
  210. a = (a << 4) | (a >> 28);
  211. a += b;
  212. d += (a ^ b ^ c) + (uint) Constants.C33 + buff [8];
  213. d = (d << 11) | (d >> 21);
  214. d += a;
  215. c += (d ^ a ^ b) + (uint) Constants.C34 + buff [11];
  216. c = (c << 16) | (c >> 16);
  217. c += d;
  218. b += (c ^ d ^ a) + (uint) Constants.C35 + buff [14];
  219. b = (b << 23) | (b >> 9);
  220. b += c;
  221. a += (b ^ c ^ d) + (uint) Constants.C36 + buff [1];
  222. a = (a << 4) | (a >> 28);
  223. a += b;
  224. d += (a ^ b ^ c) + (uint) Constants.C37 + buff [4];
  225. d = (d << 11) | (d >> 21);
  226. d += a;
  227. c += (d ^ a ^ b) + (uint) Constants.C38 + buff [7];
  228. c = (c << 16) | (c >> 16);
  229. c += d;
  230. b += (c ^ d ^ a) + (uint) Constants.C39 + buff [10];
  231. b = (b << 23) | (b >> 9);
  232. b += c;
  233. a += (b ^ c ^ d) + (uint) Constants.C40 + buff [13];
  234. a = (a << 4) | (a >> 28);
  235. a += b;
  236. d += (a ^ b ^ c) + (uint) Constants.C41 + buff [0];
  237. d = (d << 11) | (d >> 21);
  238. d += a;
  239. c += (d ^ a ^ b) + (uint) Constants.C42 + buff [3];
  240. c = (c << 16) | (c >> 16);
  241. c += d;
  242. b += (c ^ d ^ a) + (uint) Constants.C43 + buff [6];
  243. b = (b << 23) | (b >> 9);
  244. b += c;
  245. a += (b ^ c ^ d) + (uint) Constants.C44 + buff [9];
  246. a = (a << 4) | (a >> 28);
  247. a += b;
  248. d += (a ^ b ^ c) + (uint) Constants.C45 + buff [12];
  249. d = (d << 11) | (d >> 21);
  250. d += a;
  251. c += (d ^ a ^ b) + (uint) Constants.C46 + buff [15];
  252. c = (c << 16) | (c >> 16);
  253. c += d;
  254. b += (c ^ d ^ a) + (uint) Constants.C47 + buff [2];
  255. b = (b << 23) | (b >> 9);
  256. b += c;
  257. // ---- Round 4 --------
  258. a += (((~d) | b) ^ c) + (uint) Constants.C48 + buff [0];
  259. a = (a << 6) | (a >> 26);
  260. a += b;
  261. d += (((~c) | a) ^ b) + (uint) Constants.C49 + buff [7];
  262. d = (d << 10) | (d >> 22);
  263. d += a;
  264. c += (((~b) | d) ^ a) + (uint) Constants.C50 + buff [14];
  265. c = (c << 15) | (c >> 17);
  266. c += d;
  267. b += (((~a) | c) ^ d) + (uint) Constants.C51 + buff [5];
  268. b = (b << 21) | (b >> 11);
  269. b += c;
  270. a += (((~d) | b) ^ c) + (uint) Constants.C52 + buff [12];
  271. a = (a << 6) | (a >> 26);
  272. a += b;
  273. d += (((~c) | a) ^ b) + (uint) Constants.C53 + buff [3];
  274. d = (d << 10) | (d >> 22);
  275. d += a;
  276. c += (((~b) | d) ^ a) + (uint) Constants.C54 + buff [10];
  277. c = (c << 15) | (c >> 17);
  278. c += d;
  279. b += (((~a) | c) ^ d) + (uint) Constants.C55 + buff [1];
  280. b = (b << 21) | (b >> 11);
  281. b += c;
  282. a += (((~d) | b) ^ c) + (uint) Constants.C56 + buff [8];
  283. a = (a << 6) | (a >> 26);
  284. a += b;
  285. d += (((~c) | a) ^ b) + (uint) Constants.C57 + buff [15];
  286. d = (d << 10) | (d >> 22);
  287. d += a;
  288. c += (((~b) | d) ^ a) + (uint) Constants.C58 + buff [6];
  289. c = (c << 15) | (c >> 17);
  290. c += d;
  291. b += (((~a) | c) ^ d) + (uint) Constants.C59 + buff [13];
  292. b = (b << 21) | (b >> 11);
  293. b += c;
  294. a += (((~d) | b) ^ c) + (uint) Constants.C60 + buff [4];
  295. a = (a << 6) | (a >> 26);
  296. a += b;
  297. d += (((~c) | a) ^ b) + (uint) Constants.C61 + buff [11];
  298. d = (d << 10) | (d >> 22);
  299. d += a;
  300. c += (((~b) | d) ^ a) + (uint) Constants.C62 + buff [2];
  301. c = (c << 15) | (c >> 17);
  302. c += d;
  303. b += (((~a) | c) ^ d) + (uint) Constants.C63 + buff [9];
  304. b = (b << 21) | (b >> 11);
  305. b += c;
  306. _H[0] += a;
  307. _H[1] += b;
  308. _H[2] += c;
  309. _H[3] += d;
  310. }
  311. /// <summary>
  312. /// Pads and then processes the final block.
  313. /// </summary>
  314. /// <param name="inputBuffer">Buffer to grab data from.</param>
  315. /// <param name="inputOffset">Position in buffer in bytes to get data from.</param>
  316. /// <param name="inputCount">How much data in bytes in the buffer to use.</param>
  317. private void ProcessFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
  318. byte[] fooBuffer;
  319. int paddingSize;
  320. int i;
  321. uint size;
  322. paddingSize = (int)(56 - (inputCount + count) % BLOCK_SIZE_BYTES);
  323. if (paddingSize < 1)
  324. paddingSize += BLOCK_SIZE_BYTES;
  325. fooBuffer = new byte[inputCount+paddingSize+8];
  326. for (i=0; i<inputCount; i++) {
  327. fooBuffer[i] = inputBuffer[i+inputOffset];
  328. }
  329. fooBuffer[inputCount] = 0x80;
  330. for (i=inputCount+1; i<inputCount+paddingSize; i++) {
  331. fooBuffer[i] = 0x00;
  332. }
  333. size = (uint)(count+inputCount);
  334. size *= 8;
  335. fooBuffer[inputCount+paddingSize] = (byte)((size) >> 0);
  336. fooBuffer[inputCount+paddingSize+1] = (byte)((size) >> 8);
  337. fooBuffer[inputCount+paddingSize+2] = (byte)((size) >> 16);
  338. fooBuffer[inputCount+paddingSize+3] = (byte)((size) >> 24);
  339. fooBuffer[inputCount+paddingSize+4] = 0x00;
  340. fooBuffer[inputCount+paddingSize+5] = 0x00;
  341. fooBuffer[inputCount+paddingSize+6] = 0x00;
  342. fooBuffer[inputCount+paddingSize+7] = 0x00;
  343. ProcessBlock(fooBuffer, 0);
  344. if (inputCount+paddingSize+8 == 128) {
  345. ProcessBlock(fooBuffer, 64);
  346. }
  347. }
  348. private enum Constants : uint {
  349. C0 = 0xd76aa478, C1 = 0xe8c7b756, C2 = 0x242070db,
  350. C3 = 0xc1bdceee, C4 = 0xf57c0faf, C5 = 0x4787c62a,
  351. C6 = 0xa8304613, C7 = 0xfd469501, C8 = 0x698098d8,
  352. C9 = 0x8b44f7af,C10 = 0xffff5bb1,C11 = 0x895cd7be,
  353. C12 = 0x6b901122,C13 = 0xfd987193,C14 = 0xa679438e,
  354. C15 = 0x49b40821,C16 = 0xf61e2562,C17 = 0xc040b340,
  355. C18 = 0x265e5a51,C19 = 0xe9b6c7aa,C20 = 0xd62f105d,
  356. C21 = 0x02441453,C22 = 0xd8a1e681,C23 = 0xe7d3fbc8,
  357. C24 = 0x21e1cde6,C25 = 0xc33707d6,C26 = 0xf4d50d87,
  358. C27 = 0x455a14ed,C28 = 0xa9e3e905,C29 = 0xfcefa3f8,
  359. C30 = 0x676f02d9,C31 = 0x8d2a4c8a,C32 = 0xfffa3942,
  360. C33 = 0x8771f681,C34 = 0x6d9d6122,C35 = 0xfde5380c,
  361. C36 = 0xa4beea44,C37 = 0x4bdecfa9,C38 = 0xf6bb4b60,
  362. C39 = 0xbebfbc70,C40 = 0x289b7ec6,C41 = 0xeaa127fa,
  363. C42 = 0xd4ef3085,C43 = 0x04881d05,C44 = 0xd9d4d039,
  364. C45 = 0xe6db99e5,C46 = 0x1fa27cf8,C47 = 0xc4ac5665,
  365. C48 = 0xf4292244,C49 = 0x432aff97,C50 = 0xab9423a7,
  366. C51 = 0xfc93a039,C52 = 0x655b59c3,C53 = 0x8f0ccc92,
  367. C54 = 0xffeff47d,C55 = 0x85845dd1,C56 = 0x6fa87e4f,
  368. C57 = 0xfe2ce6e0,C58 = 0xa3014314,C59 = 0x4e0811a1,
  369. C60 = 0xf7537e82,C61 = 0xbd3af235,C62 = 0x2ad7d2bb,
  370. C63 = 0xeb86d391
  371. }
  372. }
  373. }