2 // System.Security.Cryptography MD5CryptoServiceProvider Class implementation
5 // Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
6 // Sebastien Pouliot (spouliot@motus.com)
8 // Copyright 2001 by Matthew S. Ford.
10 // Comment: Adapted to the Project from Mono CVS as Sebastien Pouliot suggested to enable
11 // support of Npgsql MD5 authentication in platforms which don't have support for MD5 algorithm.
21 /// C# implementation of the MD5 cryptographic hash function.
24 internal class MD5CryptoServiceProvider : MD5
27 internal sealed class MD5CryptoServiceProvider : MD5
30 private const int BLOCK_SIZE_BYTES = 64;
31 private const int HASH_SIZE_BYTES = 16;
32 private const int HASH_SIZE_BITS = 128;
33 [CLSCompliant(false)] private uint[] _H;
34 [CLSCompliant(false)] private uint count;
35 private byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
36 private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
39 /// Creates a new MD5CryptoServiceProvider.
41 public MD5CryptoServiceProvider ()
44 HashSizeValue = HASH_SIZE_BITS;
45 _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
50 ~MD5CryptoServiceProvider ()
55 protected override void Dispose (bool disposing)
57 // nothing to do (managed implementation)
61 /// Drives the hashing function.
63 /// <param name="rgb">Byte array containing the data to hash.</param>
64 /// <param name="start">Where in the input buffer to start.</param>
65 /// <param name="size">Size in bytes of the data in the buffer to hash.</param>
66 protected override void HashCore (byte[] rgb, int start, int size)
71 if (_ProcessingBufferCount != 0)
73 if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount))
75 System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
76 _ProcessingBufferCount += size;
81 i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
82 System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
83 ProcessBlock (_ProcessingBuffer, 0);
84 _ProcessingBufferCount = 0;
90 for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES)
92 ProcessBlock (rgb, start+i);
95 if (size%BLOCK_SIZE_BYTES != 0)
97 System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
98 _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
103 /// This finalizes the hash. Takes the data from the chaining variables and returns it.
105 protected override byte[] HashFinal ()
107 byte[] hash = new byte[16];
110 ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
116 hash[i*4+j] = (byte)(_H[i] >> j*8);
124 /// Resets the class after use. Called automatically after hashing is done.
126 public override void Initialize ()
129 _ProcessingBufferCount = 0;
138 /// This is the meat of the hash function. It is what processes each block one at a time.
140 /// <param name="inputBuffer">Byte array to process data from.</param>
141 /// <param name="inputOffset">Where in the byte array to start processing.</param>
142 private void ProcessBlock (byte[] inputBuffer, int inputOffset)
144 uint[] buff = new uint[16];
148 count += BLOCK_SIZE_BYTES;
152 buff[i] = (uint)(inputBuffer[inputOffset+4*i])
153 | (((uint)(inputBuffer[inputOffset+4*i+1])) << 8)
154 | (((uint)(inputBuffer[inputOffset+4*i+2])) << 16)
155 | (((uint)(inputBuffer[inputOffset+4*i+3])) << 24);
163 // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
164 // Possibly roll up if this changes.
167 // ---- Round 1 --------
169 a += (((c ^ d) & b) ^ d) + (uint) Constants.C0 + buff [0];
170 a = (a << 7) | (a >> 25);
173 d += (((b ^ c) & a) ^ c) + (uint) Constants.C1 + buff [1];
174 d = (d << 12) | (d >> 20);
177 c += (((a ^ b) & d) ^ b) + (uint) Constants.C2 + buff [2];
178 c = (c << 17) | (c >> 15);
181 b += (((d ^ a) & c) ^ a) + (uint) Constants.C3 + buff [3];
182 b = (b << 22) | (b >> 10);
185 a += (((c ^ d) & b) ^ d) + (uint) Constants.C4 + buff [4];
186 a = (a << 7) | (a >> 25);
189 d += (((b ^ c) & a) ^ c) + (uint) Constants.C5 + buff [5];
190 d = (d << 12) | (d >> 20);
193 c += (((a ^ b) & d) ^ b) + (uint) Constants.C6 + buff [6];
194 c = (c << 17) | (c >> 15);
197 b += (((d ^ a) & c) ^ a) + (uint) Constants.C7 + buff [7];
198 b = (b << 22) | (b >> 10);
201 a += (((c ^ d) & b) ^ d) + (uint) Constants.C8 + buff [8];
202 a = (a << 7) | (a >> 25);
205 d += (((b ^ c) & a) ^ c) + (uint) Constants.C9 + buff [9];
206 d = (d << 12) | (d >> 20);
209 c += (((a ^ b) & d) ^ b) + (uint) Constants.C10 + buff [10];
210 c = (c << 17) | (c >> 15);
213 b += (((d ^ a) & c) ^ a) + (uint) Constants.C11 + buff [11];
214 b = (b << 22) | (b >> 10);
217 a += (((c ^ d) & b) ^ d) + (uint) Constants.C12 + buff [12];
218 a = (a << 7) | (a >> 25);
221 d += (((b ^ c) & a) ^ c) + (uint) Constants.C13 + buff [13];
222 d = (d << 12) | (d >> 20);
225 c += (((a ^ b) & d) ^ b) + (uint) Constants.C14 + buff [14];
226 c = (c << 17) | (c >> 15);
229 b += (((d ^ a) & c) ^ a) + (uint) Constants.C15 + buff [15];
230 b = (b << 22) | (b >> 10);
234 // ---- Round 2 --------
236 a += (((b ^ c) & d) ^ c) + (uint) Constants.C16 + buff [1];
237 a = (a << 5) | (a >> 27);
240 d += (((a ^ b) & c) ^ b) + (uint) Constants.C17 + buff [6];
241 d = (d << 9) | (d >> 23);
244 c += (((d ^ a) & b) ^ a) + (uint) Constants.C18 + buff [11];
245 c = (c << 14) | (c >> 18);
248 b += (((c ^ d) & a) ^ d) + (uint) Constants.C19 + buff [0];
249 b = (b << 20) | (b >> 12);
252 a += (((b ^ c) & d) ^ c) + (uint) Constants.C20 + buff [5];
253 a = (a << 5) | (a >> 27);
256 d += (((a ^ b) & c) ^ b) + (uint) Constants.C21 + buff [10];
257 d = (d << 9) | (d >> 23);
260 c += (((d ^ a) & b) ^ a) + (uint) Constants.C22 + buff [15];
261 c = (c << 14) | (c >> 18);
264 b += (((c ^ d) & a) ^ d) + (uint) Constants.C23 + buff [4];
265 b = (b << 20) | (b >> 12);
268 a += (((b ^ c) & d) ^ c) + (uint) Constants.C24 + buff [9];
269 a = (a << 5) | (a >> 27);
272 d += (((a ^ b) & c) ^ b) + (uint) Constants.C25 + buff [14];
273 d = (d << 9) | (d >> 23);
276 c += (((d ^ a) & b) ^ a) + (uint) Constants.C26 + buff [3];
277 c = (c << 14) | (c >> 18);
280 b += (((c ^ d) & a) ^ d) + (uint) Constants.C27 + buff [8];
281 b = (b << 20) | (b >> 12);
284 a += (((b ^ c) & d) ^ c) + (uint) Constants.C28 + buff [13];
285 a = (a << 5) | (a >> 27);
288 d += (((a ^ b) & c) ^ b) + (uint) Constants.C29 + buff [2];
289 d = (d << 9) | (d >> 23);
292 c += (((d ^ a) & b) ^ a) + (uint) Constants.C30 + buff [7];
293 c = (c << 14) | (c >> 18);
296 b += (((c ^ d) & a) ^ d) + (uint) Constants.C31 + buff [12];
297 b = (b << 20) | (b >> 12);
301 // ---- Round 3 --------
303 a += (b ^ c ^ d) + (uint) Constants.C32 + buff [5];
304 a = (a << 4) | (a >> 28);
307 d += (a ^ b ^ c) + (uint) Constants.C33 + buff [8];
308 d = (d << 11) | (d >> 21);
311 c += (d ^ a ^ b) + (uint) Constants.C34 + buff [11];
312 c = (c << 16) | (c >> 16);
315 b += (c ^ d ^ a) + (uint) Constants.C35 + buff [14];
316 b = (b << 23) | (b >> 9);
319 a += (b ^ c ^ d) + (uint) Constants.C36 + buff [1];
320 a = (a << 4) | (a >> 28);
323 d += (a ^ b ^ c) + (uint) Constants.C37 + buff [4];
324 d = (d << 11) | (d >> 21);
327 c += (d ^ a ^ b) + (uint) Constants.C38 + buff [7];
328 c = (c << 16) | (c >> 16);
331 b += (c ^ d ^ a) + (uint) Constants.C39 + buff [10];
332 b = (b << 23) | (b >> 9);
335 a += (b ^ c ^ d) + (uint) Constants.C40 + buff [13];
336 a = (a << 4) | (a >> 28);
339 d += (a ^ b ^ c) + (uint) Constants.C41 + buff [0];
340 d = (d << 11) | (d >> 21);
343 c += (d ^ a ^ b) + (uint) Constants.C42 + buff [3];
344 c = (c << 16) | (c >> 16);
347 b += (c ^ d ^ a) + (uint) Constants.C43 + buff [6];
348 b = (b << 23) | (b >> 9);
351 a += (b ^ c ^ d) + (uint) Constants.C44 + buff [9];
352 a = (a << 4) | (a >> 28);
355 d += (a ^ b ^ c) + (uint) Constants.C45 + buff [12];
356 d = (d << 11) | (d >> 21);
359 c += (d ^ a ^ b) + (uint) Constants.C46 + buff [15];
360 c = (c << 16) | (c >> 16);
363 b += (c ^ d ^ a) + (uint) Constants.C47 + buff [2];
364 b = (b << 23) | (b >> 9);
368 // ---- Round 4 --------
370 a += (((~d) | b) ^ c) + (uint) Constants.C48 + buff [0];
371 a = (a << 6) | (a >> 26);
374 d += (((~c) | a) ^ b) + (uint) Constants.C49 + buff [7];
375 d = (d << 10) | (d >> 22);
378 c += (((~b) | d) ^ a) + (uint) Constants.C50 + buff [14];
379 c = (c << 15) | (c >> 17);
382 b += (((~a) | c) ^ d) + (uint) Constants.C51 + buff [5];
383 b = (b << 21) | (b >> 11);
386 a += (((~d) | b) ^ c) + (uint) Constants.C52 + buff [12];
387 a = (a << 6) | (a >> 26);
390 d += (((~c) | a) ^ b) + (uint) Constants.C53 + buff [3];
391 d = (d << 10) | (d >> 22);
394 c += (((~b) | d) ^ a) + (uint) Constants.C54 + buff [10];
395 c = (c << 15) | (c >> 17);
398 b += (((~a) | c) ^ d) + (uint) Constants.C55 + buff [1];
399 b = (b << 21) | (b >> 11);
402 a += (((~d) | b) ^ c) + (uint) Constants.C56 + buff [8];
403 a = (a << 6) | (a >> 26);
406 d += (((~c) | a) ^ b) + (uint) Constants.C57 + buff [15];
407 d = (d << 10) | (d >> 22);
410 c += (((~b) | d) ^ a) + (uint) Constants.C58 + buff [6];
411 c = (c << 15) | (c >> 17);
414 b += (((~a) | c) ^ d) + (uint) Constants.C59 + buff [13];
415 b = (b << 21) | (b >> 11);
418 a += (((~d) | b) ^ c) + (uint) Constants.C60 + buff [4];
419 a = (a << 6) | (a >> 26);
422 d += (((~c) | a) ^ b) + (uint) Constants.C61 + buff [11];
423 d = (d << 10) | (d >> 22);
426 c += (((~b) | d) ^ a) + (uint) Constants.C62 + buff [2];
427 c = (c << 15) | (c >> 17);
430 b += (((~a) | c) ^ d) + (uint) Constants.C63 + buff [9];
431 b = (b << 21) | (b >> 11);
442 /// Pads and then processes the final block.
444 /// <param name="inputBuffer">Buffer to grab data from.</param>
445 /// <param name="inputOffset">Position in buffer in bytes to get data from.</param>
446 /// <param name="inputCount">How much data in bytes in the buffer to use.</param>
447 private void ProcessFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
454 paddingSize = (int)(56 - (inputCount + count) % BLOCK_SIZE_BYTES);
457 paddingSize += BLOCK_SIZE_BYTES;
460 fooBuffer = new byte[inputCount+paddingSize+8];
462 for (i=0; i<inputCount; i++)
464 fooBuffer[i] = inputBuffer[i+inputOffset];
467 fooBuffer[inputCount] = 0x80;
468 for (i=inputCount+1; i<inputCount+paddingSize; i++)
473 size = (uint)(count+inputCount);
475 fooBuffer[inputCount+paddingSize] = (byte)((size) >> 0);
476 fooBuffer[inputCount+paddingSize+1] = (byte)((size) >> 8);
477 fooBuffer[inputCount+paddingSize+2] = (byte)((size) >> 16);
478 fooBuffer[inputCount+paddingSize+3] = (byte)((size) >> 24);
480 fooBuffer[inputCount+paddingSize+4] = 0x00;
481 fooBuffer[inputCount+paddingSize+5] = 0x00;
482 fooBuffer[inputCount+paddingSize+6] = 0x00;
483 fooBuffer[inputCount+paddingSize+7] = 0x00;
485 ProcessBlock(fooBuffer, 0);
487 if (inputCount+paddingSize+8 == 128)
489 ProcessBlock(fooBuffer, 64);
493 private enum Constants :
495 C0 = 0xd76aa478, C1 = 0xe8c7b756, C2 = 0x242070db,
496 C3 = 0xc1bdceee, C4 = 0xf57c0faf, C5 = 0x4787c62a,
497 C6 = 0xa8304613, C7 = 0xfd469501, C8 = 0x698098d8,
498 C9 = 0x8b44f7af,C10 = 0xffff5bb1,C11 = 0x895cd7be,
499 C12 = 0x6b901122,C13 = 0xfd987193,C14 = 0xa679438e,
500 C15 = 0x49b40821,C16 = 0xf61e2562,C17 = 0xc040b340,
501 C18 = 0x265e5a51,C19 = 0xe9b6c7aa,C20 = 0xd62f105d,
502 C21 = 0x02441453,C22 = 0xd8a1e681,C23 = 0xe7d3fbc8,
503 C24 = 0x21e1cde6,C25 = 0xc33707d6,C26 = 0xf4d50d87,
504 C27 = 0x455a14ed,C28 = 0xa9e3e905,C29 = 0xfcefa3f8,
505 C30 = 0x676f02d9,C31 = 0x8d2a4c8a,C32 = 0xfffa3942,
506 C33 = 0x8771f681,C34 = 0x6d9d6122,C35 = 0xfde5380c,
507 C36 = 0xa4beea44,C37 = 0x4bdecfa9,C38 = 0xf6bb4b60,
508 C39 = 0xbebfbc70,C40 = 0x289b7ec6,C41 = 0xeaa127fa,
509 C42 = 0xd4ef3085,C43 = 0x04881d05,C44 = 0xd9d4d039,
510 C45 = 0xe6db99e5,C46 = 0x1fa27cf8,C47 = 0xc4ac5665,
511 C48 = 0xf4292244,C49 = 0x432aff97,C50 = 0xab9423a7,
512 C51 = 0xfc93a039,C52 = 0x655b59c3,C53 = 0x8f0ccc92,
513 C54 = 0xffeff47d,C55 = 0x85845dd1,C56 = 0x6fa87e4f,
514 C57 = 0xfe2ce6e0,C58 = 0xa3014314,C59 = 0x4e0811a1,
515 C60 = 0xf7537e82,C61 = 0xbd3af235,C62 = 0x2ad7d2bb,