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