1 using System; 2 using System.IO; 3 // MD5 Alogrithm 4 // by liwei 2013.3.12 http://www.cnblogs.com/Okalun/ 5 // 伪代码 6 7 ////Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating 8 //var int[64] r, k 9 10 ////r specifies the per-round shift amounts 11 //r[ 0..15]:= {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22} 12 //r[16..31]:= {5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20} 13 //r[32..47]:= {4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23} 14 //r[48..63]:= {6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21} 15 16 ////Use binary integer part of the sines of integers as constants: 17 //for i from 0 to 63 18 // k[i] := floor(abs(sin(i + 1)) × 2^32) 19 20 ////Initialize variables: 21 //var int h0 := 0x67452301 22 //var int h1 := 0xEFCDAB89 23 //var int h2 := 0x98BADCFE 24 //var int h3 := 0x10325476 25 26 ////Pre-processing: 27 //append "1" bit to message 28 //append "0" bits until message length in bits ≡ 448 (mod 512) 29 //append bit length of message as 64-bit little-endian integer to message 30 31 ////Process the message in successive 512-bit chunks: 32 //for each 512-bit chunk of message 33 // break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15 34 35 // //Initialize hash value for this chunk: 36 // var int a := h0 37 // var int b := h1 38 // var int c := h2 39 // var int d := h3 40 41 // //Main loop: 42 // for i from 0 to 63 43 // if 0 ≤ i ≤ 15 then 44 // f := (b and c) or ((not b) and d) 45 // g := i 46 // else if 16 ≤ i ≤ 31 47 // f := (d and b) or ((not d) and c) 48 // g := (5×i + 1) mod 16 49 // else if 32 ≤ i ≤ 47 50 // f := b xor c xor d 51 // g := (3×i + 5) mod 16 52 // else if 48 ≤ i ≤ 63 53 // f := c xor (b or (not d)) 54 // g := (7×i) mod 16 55 56 // temp := d 57 // d := c 58 // c := b 59 // b := leftrotate((a + f + k[i] + w[g]),r[i]) + b 60 // a := temp 61 // Next i 62 // //Add this chunk's hash to result so far: 63 // h0 := h0 + a 64 // h1 := h1 + b 65 // h2 := h2 + c 66 // h3 := h3 + d 67 //End ForEach 68 //var int digest := h0 append h1 append h2 append h3 //(expressed as little-endian) 69 namespace HashEncrypted 70 { 71 class MD5 72 { 73 private static int[] leftrotates = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 74 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 75 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 76 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 77 }; 78 private static uint[] table = new uint[64]; 79 private static uint[] tempresults = new uint[4]; 80 private static byte[] MD5ByteArray = new byte[16]; 81 private static byte[] PaddingData = {128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84 0, 0, 0, 0 }; 85 86 private string hexOutput = ""; 87 public string MD5HexOutput 88 { 89 get 90 { 91 for (int i = 0; i < 16; i++) 92 { 93 hexOutput += String.Format("{0:x2}", MD5ByteArray[i]); 94 } 95 return hexOutput; 96 } 97 } 98 99 static MD5() 100 { 101 for (int i = 0; i < table.Length; i++) 102 { 103 table[i] = (uint)Math.Floor(Math.Abs(Math.Sin(i + 1)) * (2L << 31)); 104 }; 105 } 106 107 private static void MD5Init() 108 { 109 tempresults[0] = 0x67452301; //in memory, this is 0x01234567 110 tempresults[1] = 0xefcdab89; //in memory, this is 0x89abcdef 111 tempresults[2] = 0x98badcfe; //in memory, this is 0xfedcba98 112 tempresults[3] = 0x10325476; //in memory, this is 0x76543210 113 } 114 115 private static byte[] UlongToBytes(ulong inputUlong) 116 { 117 byte[] outputBytes = new byte[8]; 118 for (int i = 0; i < 8; i++) 119 { 120 outputBytes[7 - i] = (byte)((inputUlong >> 8 * (7 - i)) & 0xFF); 121 } 122 return outputBytes; 123 } 124 125 private static uint LeftRotate(uint num, int bit) 126 { 127 return (num << bit) | (num >> (32 - bit)); 128 } 129 130 private static uint[] MD5Append(byte[] Source, long SourceLength) 131 { 132 int paddedLength; 133 int needPaddingSize; 134 int paddingSourceLength = Source.Length; 135 byte[] paddedSource; 136 byte[] lengthBytes = UlongToBytes((ulong)SourceLength * 8); 137 138 paddedLength = (64 * (paddingSourceLength / 64 + 1)); 139 paddedSource = new byte[paddedLength]; 140 needPaddingSize = (paddedLength - paddingSourceLength - 8); 141 142 for (int i = 0; i < paddedLength; i++) 143 { 144 if (i < paddingSourceLength) 145 { 146 paddedSource[i] = Source[i]; 147 } 148 else if (i < needPaddingSize + paddingSourceLength) 149 { 150 paddedSource[i] = PaddingData[i - paddingSourceLength]; 151 } 152 else 153 { 154 paddedSource[i] = lengthBytes[i - paddingSourceLength - needPaddingSize]; 155 } 156 } 157 158 uint[] target = new uint[paddedLength / 4]; 159 for (int i = 0, j = 0; i < paddedLength; j++, i += 4) 160 { 161 target[j] = (uint)(paddedSource[i] | paddedSource[i + 1] << 8 | paddedSource[i + 2] << 16 | paddedSource[i + 3] << 24); 162 } 163 return target; 164 } 165 166 private static void MD5Trasform(uint[] input) 167 { 168 uint a = tempresults[0]; 169 uint b = tempresults[1]; 170 uint c = tempresults[2]; 171 uint d = tempresults[3]; 172 uint calValue; 173 uint index; 174 175 for (uint i = 0; i < 64; i++) 176 { 177 if (i <= 15) 178 { 179 calValue = (b & c) | ((~b) & d); 180 index = i; 181 } 182 else if (i <= 31) 183 { 184 calValue = (d & b) | ((~d) & c); 185 index = (5 * i + 1) % 16; 186 } 187 else if (i <= 47) 188 { 189 calValue = b ^ c ^ d; 190 index = (3 * i + 5) % 16; 191 } 192 else 193 { 194 calValue = c ^ (b | (~d)); 195 index = (7 * i) % 16; 196 } 197 198 uint temp = a + calValue + table[i] + input[index]; 199 temp = LeftRotate(temp, leftrotates[i]); 200 a = b + temp; 201 202 temp = d; 203 d = c; 204 c = b; 205 b = a; 206 a = temp; 207 } 208 209 tempresults[0] += a; 210 tempresults[1] += b; 211 tempresults[2] += c; 212 tempresults[3] += d; 213 } 214 215 private static void GetMD5ByteArray(uint[] MD5UnintArray) 216 { 217 MD5ByteArray = new byte[16]; 218 for (int i = 0, j = 0; i < 4; i++, j += 4) 219 { 220 MD5ByteArray[j] = (byte)(MD5UnintArray[i] & 0xff); 221 MD5ByteArray[j + 1] = (byte)((MD5UnintArray[i] >> 8) & 0xff); 222 MD5ByteArray[j + 2] = (byte)((MD5UnintArray[i] >> 16) & 0xff); 223 MD5ByteArray[j + 3] = (byte)((MD5UnintArray[i] >> 24) & 0xff); 224 } 225 } 226 227 private static void MD5BytesDigest(byte[] Date) 228 { 229 uint[] PaddedData; 230 uint[] block = new uint[16]; 231 MD5Init(); 232 PaddedData = MD5Append(Date, (long)Date.Length); 233 234 for (int i = 0; i < PaddedData.Length / 16; i++) 235 { 236 for (int j = 0; j < 16; j++) 237 { 238 block[j] = PaddedData[i * 16 + j]; 239 } 240 MD5Trasform(block); 241 } 242 GetMD5ByteArray(tempresults); 243 } 244 245 public MD5(byte[] Date) 246 { 247 MD5BytesDigest(Date); 248 } 249 250 public MD5(string StringDate) 251 { 252 MD5BytesDigest(System.Text.Encoding.Default.GetBytes(StringDate)); 253 } 254 255 public MD5(FileInfo fileInfo) 256 { 257 byte[] buffer = new byte[64]; 258 byte[] lastDateBuffer; 259 uint[] paddedLastData; 260 uint[] block = new uint[16]; 261 MD5Init(); 262 263 try 264 { 265 using (FileStream fs = fileInfo.OpenRead()) 266 { 267 int numBytesToRead = 0; 268 269 270 while (true) 271 { 272 int readLength; 273 readLength = fs.Read(buffer, 0, buffer.Length); 274 if (readLength == 64) 275 { 276 for (int i = 0, j = 0; j < 16; j++, i += 4) 277 { 278 block[j] = (uint)(buffer[i] | buffer[i + 1] << 8 | buffer[i + 2] << 16 | buffer[i + 3] << 24); 279 } 280 MD5Trasform(block); 281 } 282 else 283 { 284 lastDateBuffer = new byte[fs.Length - numBytesToRead]; 285 for (int i = 0; i < readLength; i++) 286 { 287 lastDateBuffer[i] = buffer[i]; 288 } 289 paddedLastData = MD5Append(lastDateBuffer, fs.Length); 290 291 for (int j = 0; j < 16; j++) 292 { 293 block[j] = paddedLastData[j]; 294 } 295 MD5Trasform(block); 296 break; 297 } 298 numBytesToRead += readLength; 299 } 300 } 301 } 302 catch (FileNotFoundException ioEx) 303 { 304 Console.WriteLine(ioEx.Message); 305 } 306 GetMD5ByteArray(tempresults); 307 } 308 } 309 310 class Program 311 { 312 private static void StringTest(string input) 313 { 314 MD5 m = new MD5(input); 315 Console.WriteLine("MD5(\"" + input + "\")=" + m.MD5HexOutput); 316 } 317 318 private static void FileTest(string filename) 319 { 320 FileInfo fi = new FileInfo(filename); 321 MD5 f = new MD5(fi); 322 Console.WriteLine("file :" + filename + " MD5 is " + f.MD5HexOutput); 323 } 324 325 private static void Test() 326 { 327 StringTest(""); 328 StringTest("a"); 329 StringTest("abc"); 330 StringTest("message digest"); 331 FileTest(@"C#本质论源代码.zip"); 332 Console.ReadKey(); 333 } 334 335 static void Main(string[] args) 336 { 337 Test(); 338 } 339 } 340 }