// Copyright (c) Microsoft Corporation. all rights reserved. <br/> using system; <br/> using system. text; <br/> //********************************** * ************************* <br/> // * Raw Implementation of the MD5 hash Algorithm <br/> // * From RFC 1321. <br/> // * written by: reid borsuk and Jenny Zheng <br/> // * copyright (c) Microsoft Corporation. all rights reserved. <br/> //********************************** * ************************* <br/> // simple struct for the (, b, C, D) which is used to compute the mesage digest. <br/> struct abcdstruct <br/> {<br/> Public uint A; <br/> Public uint B; <br/> Public uint C; <br/> Public uint D; <br/>}< br/> Public sealed class md5core <br/> {<br/> // prevent CSC from adding a default public constructor <br/> private md5core () {}< br/> Public static byte [] gethash (string input, encoding) <br/>{< br/> If (null = input) <br/> throw new system. argumentnullexception ("input", "unable to calculate hash over null input data"); <br/> If (null = encoding) <br/> throw new system. argumentnullexception ("encoding", "unable to calculate hash over a string without a default encoding. consider using the gethash (string) overload to use utf8 encoding "); <br/> byte [] target = encoding. getbytes (input); <br/> return gethash (target); <br/>}< br/> Public static byte [] gethash (string input) <br/>{< br/> return gethash (input, new utf8encoding (); <br/>}< br/> Public static string gethashstring (byte [] input) <br/>{< br/> If (null = input) <br/> throw new system. argumentnullexception ("input", "unable to calculate hash over null input data"); <br/> string retval = bitconverter. tostring (gethash (input); <br/> retval = retval. replace ("-", ""); <br/> return retval; <br/>}< br/> Public static string gethashstring (string input, encoding) <br/>{< br/> If (null = input) <br/> throw new system. argumentnullexception ("input", "unable to calculate hash over null input data"); <br/> If (null = encoding) <br/> throw new system. argumentnullexception ("encoding", "unable to calculate hash over a string without a default encoding. consider using the gethashstring (string) overload to use utf8 encoding "); </P> <p> byte [] target = encoding. getbytes (input); <br/> return gethashstring (target); <br/>}< br/> Public static string gethashstring (string input) <br/>{< br/> return gethashstring (input, new utf8encoding ()); <br/>}< br/> Public static byte [] gethash (byte [] input) <br/>{< br/> If (null = input) <br/> throw new system. argumentnullexception ("input", "unable to calculate hash over null input data "); <br/> // intitial values defined in RFC 1321 <br/> abcdstruct ABCD = new abcdstruct (); <br/> ABCD. a = 0x67452301; <br/> ABCD. B = 0xefcdab89; <br/> ABCD. C = 0x98badcfe; <br/> ABCD. D = 0x10325476; <br/> // we pass in the input array by block, the final block of data must be handled specialy for padding & length embeding <br/> int startindex = 0; <br/> while (startindex <= input. length-64) <br/>{< br/> md5core. gethashblock (input, ref ABCD, startindex); <br/> startindex + = 64; <br/>}< br/> // the final data block. <br/> return md5core. gethashfinalblock (input, startindex, input. length-startindex, ABCD, (int64) input. length * 8); <br/>}< br/> internal static byte [] gethashfinalblock (byte [] input, int ibstart, int cbsize, abcdstruct ABCD, int64 Len) <br/> {<br/> byte [] Working = new byte [64]; <br/> byte [] length = bitconverter. getbytes (LEN); <br/> // padding is a single bit 1, followed by the number of 0 s required to make size congruent to 448 modulo 512. step 1 of RFC 1321 <br/> // the CLR ensures that our buffer is 0-assigned, we don't need to explicitly set it. this is why it ends up being quicker to just <br/> // use a temporary array rather then doing in-place assignment (5% for small inputs) <br/> array. copy (input, ibstart, working, 0, cbsize); <br/> working [cbsize] = 0x80; <br/> // we have enough room to store the length in this chunk <br/> If (cbsize <= 56) <br/>{< br/> array. copy (length, 0, working, 56, 8); <br/> gethashblock (working, ref ABCD, 0 ); <br/>}< br/> else // we need an aditional chunk to store the length <br/>{< br/> gethashblock (working, ref ABCD, 0 ); <br/> // create an entirely new chunk due to the 0-assigned Trick mentioned above, to avoid an extra function call Clearing the array <br/> working = new byte [64]; <br/> array. copy (length, 0, working, 56, 8); <br/> gethashblock (working, ref ABCD, 0 ); <br/>}< br/> byte [] Output = new byte [16]; <br/> array. copy (bitconverter. getbytes (ABCD. a), 0, output, 0, 4); <br/> array. copy (bitconverter. getbytes (ABCD. b), 0, output, 4, 4); <br/> array. copy (bitconverter. getbytes (ABCD. c), 0, output, 8, 4); <br/> array. copy (bitconverter. getbytes (ABCD. d), 0, output, 12, 4); <br/> return output; <br/>}< br/> // performs a single block transform of MD5 for a given set of ABCD inputs <br/>/* If implementing your own hashing framework, be sure to set the initial ABCD correctly according to RFC 1321: <br/> // a = 0x67452301; <br/> // B = 0xefcdab89; <br/> // C = 0x98badcfe; <br/> // D = 0x10325476; <br/> */<br/> internal static void gethashblock (byte [] input, ref abcdstruct abcdvalue, int ibstart) <br/>{< br/> uint [] temp = converter (input, ibstart); <br/> uint A = abcdvalue. a; <br/> uint B = abcdvalue. b; <br/> uint c = abcdvalue. c; <br/> uint d = abcdvalue. d; <br/> A = R1 (a, B, c, d, temp [0], 7, 0xd76aa478); <br/> d = R1 (D,, b, c, temp [1], 12, 0xe8c7b756); <br/> C = R1 (c, d, A, B, temp [2], 17, 0x242070db ); <br/> B = R1 (B, c, d, A, temp [3], 22, 0xc1bdceee); <br/> A = R1 (a, B, c, d, temp [4], 7, 0xf57c0faf); <br/> d = R1 (D, a, B, c, temp [5], 12, 0x4787c62a ); <br/> C = R1 (c, d, A, B, temp [6], 17, 0xa8304613); <br/> B = R1 (B, c, d, a, temp [7], 22, 0xfd469501); <br/> A = R1 (a, B, c, d, temp [8], 7, 0x698098d8 ); <br/> d = R1 (D, a, B, c, temp [9], 12, 0x8b44f7af); <br/> C = R1 (c, d,, b, temp [10], 17, 0xffff5bb1); <br/> B = R1 (B, c, d, A, temp [11], 22, 0x895cd7be ); <br/> A = R1 (a, B, c, d, temp [12], 7, 0x6b901122); <br/> d = R1 (D, A, B, c, temp [13], 12, 0xfd987193); <br/> C = R1 (c, d, A, B, temp [14], 17, 0xa679438e ); <br/> B = R1 (B, c, d, A, temp [15], 22, 0x49b40821); <br/> A = R2 (a, B, c, d, temp [1], 5, 0xf61e2562); <br/> d = R2 (D, a, B, c, temp [6], 9, 0xc040b340 ); <br/> C = R2 (c, d, A, B, temp [11], 14, 0x265e5a51); <br/> B = R2 (B, c, d, a, temp [0], 20, 0xe9b6c7aa); <br/> A = R2 (a, B, c, d, temp [5], 5, 0xd62f105d ); <br/> d = R2 (D, a, B, c, temp [10], 9, 0x02441453); <br/> C = R2 (c, d, a, B, temp [15], 14, 0xd8a1e681); <br/> B = R2 (B, c, d, A, temp [4], 20, 0xe7d3fbc8 ); <br/> A = R2 (a, B, c, d, temp [9], 5, 0x21e1cde6); <br/> d = R2 (D, A, B, c, temp [14], 9, 0xc33707d6); <br/> C = R2 (c, d, A, B, temp [3], 14, 0xf4d50d87 ); <br/> B = R2 (B, c, d, A, temp [8], 20, 0x455a14ed); <br/> A = R2 (a, B, c, d, temp [13], 5, 0xa9e3e905); <br/> d = R2 (D, a, B, c, temp [2], 9, 0xfcefa3f8 ); <br/> C = R2 (c, d, A, B, temp [7], 14, 0x676f02d9); <br/> B = R2 (B, c, d, a, temp [12], 20, 0x8d2a4c8a); <br/> A = R3 (a, B, c, d, temp [5], 4, 0xfffa3942 ); <br/> d = R3 (D, a, B, c, temp [8], 11, 0x8771f681); <br/> C = R3 (c, d,, b, temp [11], 16, 0x6d9d6122); <br/> B = R3 (B, c, d, A, temp [14], 23, 0xfde5380c ); <br/> A = R3 (a, B, c, d, temp [1], 4, 0xa4beea44); <br/> d = R3 (D, A, B, c, temp [4], 11, 0x4bdecfa9); <br/> C = R3 (c, d, A, B, temp [7], 16, 0xf6bb4b60 ); <br/> B = R3 (B, c, d, A, temp [10], 23, 0xbebfbc70); <br/> A = R3 (a, B, c, d, temp [13], 4, 0x289b7ec6); <br/> d = R3 (D, a, B, c, temp [0], 11, 0xeaa1_fa ); <br/> C = R3 (c, d, A, B, temp [3], 16, 0xd4ef3085); <br/> B = R3 (B, c, d, a, temp [6], 23, 0x04881d05); <br/> A = R3 (a, B, c, d, temp [9], 4, 0xd9d4d039 ); <br/> d = R3 (D, a, B, c, temp [12], 11, 0xe6db99e5); <br/> C = R3 (c, d,, b, temp [15], 16, 0x1fa27cf8); <br/> B = R3 (B, c, d, A, temp [2], 23, 0xc4ac5665 ); <br/> A = R4 (a, B, c, d, temp [0], 6, 0xf4292244); <br/> d = R4 (D, A, B, c, temp [7], 10, 0x432aff97); <br/> C = R4 (c, d, A, B, temp [14], 15, 0xab9423a7 ); <br/> B = R4 (B, c, d, A, temp [5], 21, 0xfc93a039); <br/> A = R4 (a, B, c, d, temp [12], 6, 0x655b59c3); <br/> d = R4 (D, a, B, c, temp [3], 10, 0x8f0ccc92 ); <br/> C = R4 (c, d, A, B, temp [10], 15, 0xffeff47d); <br/> B = R4 (B, c, d, a, temp [1], 21, 0x85845dd1); <br/> A = R4 (a, B, c, d, temp [8], 6, 0x6fa87e4f ); <br/> d = R4 (D, a, B, c, temp [15], 10, 0xfe2ce6e0); <br/> C = R4 (c, d,, b, temp [6], 15, 0xa3014314); <br/> B = R4 (B, c, d, A, temp [13], 21, 0x4e0811a1 ); <br/> A = R4 (a, B, c, d, temp [4], 6, 0xf7537e82); <br/> d = R4 (D, A, B, c, temp [11], 10, 0xbd3af235); <br/> C = R4 (c, d, A, B, temp [2], 15, 0x2ad7d2bb ); <br/> B = R4 (B, c, d, A, temp [9], 21, 0xeb86d391); <br/> abcdvalue. A = unchecked (a + abcdvalue. a); <br/> abcdvalue. B = unchecked (B + abcdvalue. b); <br/> abcdvalue. C = unchecked (C + abcdvalue. c); <br/> abcdvalue. D = unchecked (D + abcdvalue. d); <br/> return; <br/>}< br/> // manually unrolling these equations nets us a 20% Performance Improvement <br/> Private Static uint r1 (uint A, uint B, uint C, uint D, uint X, int S, uint t) <br/>{< br/> // (B + LSR (a + F (B, c, d) + x + T), S) <br/> // F (x, y, z) (X & Y) | (x ^ 0 xffffffff) & Z) <br/> return unchecked (B + LSR (a + (B & C) | (B ^ 0 xffffffff) & D )) + x + T), S); <br/>}< br/> Private Static uint R2 (uint A, uint B, uint C, uint D, uint X, int S, uint t) <br/>{< br/> // (B + LSR (a + g (B, c, d) + x + T ), s) <br/> // g (x, y, z) (X & z) | (Y & (Z ^ 0 xffffffff ))) <br/> return unchecked (B + LSR (a + (B & D) | (C & (d ^ 0 xffffffff) + x + T ), s); <br/>}< br/> Private Static uint R3 (uint A, uint B, uint C, uint D, uint X, int S, uint T) <br/> {<br/> // (B + LSR (a + H (B, c, d) + K + I), S )) <br/> // h (x, y, z) (x ^ y ^ Z) <br/> return unchecked (B + LSR (a + (B ^ C ^ D) + x + T), s )); <br/>}< br/> Private Static uint R4 (uint A, uint B, uint C, uint D, uint X, int S, uint T) <br/> {<br/> // (B + LSR (a + I (B, C, D) + K + I), S )) <br/> // I (x, y, z) (y ^ (X | (Z ^ 0 xffffffff ))) <br/> return unchecked (B + LSR (a + (C ^ (B | (d ^ 0 xffffffff) + x + T), s )); <br/>}< br/> // Implementation of left rotate <br/> // s is an int instead of a uint becuase the CLR requires the argument passed to>/ <is of <br/> // type Int. doing the demoting inside this function wocould add overhead. <br/> Private Static uint LSR (uint I, int s) <br/>{< br/> return (I <s) | (I> (32-s ))); <br/>}< br/> // convert input array into array of uints <br/> Private Static uint [] converter (byte [] input, int ibstart) <br/>{< br/> If (null = input) <br/> throw new system. argumentnullexception ("input", "Unable convert null array to array of uints"); </P> <p> uint [] result = new uint [16]; </P> <p> for (INT I = 0; I <16; I ++) <br/> {<br/> result [I] = (uint) input [ibstart + I * 4]; <br/> result [I] + = (uint) input [ibstart + I * 4 + 1] <8; <br/> result [I] + = (uint) input [ibstart + I * 4 + 2] <16; <br/> result [I] + = (uint) input [ibstart + I * 4 + 3] <24; <br/>}</P> <p> return result; <br/>}< br/>}
Call: bitconverter. tostring (md5core. gethash (key ))