C#中計算流指定位置和長度的MD5值

iDotNetSpace發表於2009-07-29

在Microsoft .NET Framework 2.0中,計算MD5值可以用到System.Security.Cryptography.MD5CryptoServiceProvider類,其計算MD5的方法ComputeHash()有三個過載方法。


名稱說明

ComputeHash(Byte[])計算指定位元組陣列的雜湊值。 (繼承自 HashAlgorithm。)

ComputeHash(Stream)計算指定 Stream 物件的雜湊值。 (繼承自 HashAlgorithm。)

ComputeHash(Byte[], Int32, Int32)計算指定位元組陣列的指定區域的雜湊值。 (繼承自 HashAlgorithm。)

如果需要計算檔案流中指定區域的雜湊值(如大檔案傳輸斷點續傳)時,這三個方法就不夠用了,我們需要一個如下的過載方法:


名稱說明

ComputeHash(Stream,Int32,Int32)計算指定 Stream 物件的指定區域的雜湊值。(繼承自 HashAlgorithm。)

  

不過微軟並沒有提供這個方法來計算流中指定區域的MD5值。通過反編譯mscorlib.dll與檢視微軟公佈的Framework部分原始碼,發現Windows 2000 Professol與Windows XP及以上作業系統提供了一個 "Cryptdll.dll”,其中有3個關於計算MD5的API函式:

MD5Init

The MD5Init function initializes an MD5 message digest context. The context must be initialized for any new MD5 message digest. This function is defined by RSA.

void MD5Init(
MD5_CTX* context
);

MD5Update

The MD5Update function updates the MD5 context by using the supplied buffer for the message whose MD5 digest is being generated. This function is called for each buffer of the message being hashed. This function is defined by RSA.

void MD5Update(
MD5_CTX context,
unsigned char* input,
unsigned int inlen
);

MD5Final

The MD5Final function ends an MD5 message digest previously started by a call to the MD5Init function. Prior to calling MD5Final, use the MD5Update function to update the MD5 message digest context with each buffer in the message being hashed. This function is defined by RSA.

void MD5Final(
MD5_CTX context
);
有了這些準備,就可以實現計算流中指定區域的MD5值了,下面是MyMD5類的原始碼:
 1       public sealed class MyMD5 : HashAlgorithm
 2       {          [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
 3           public struct MD5_CTX
 4           {
 5               /// ULONG[2]              [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = System.Runtime.InteropServices.UnmanagedType.U4)]
 6               public uint[] i;
 7               /// ULONG[4]              [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.U4)]
 8               public uint[] buf;
 9               /// unsigned char[64]              [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 64)]
10               public byte[] @in;
11               /// unsigned char[16]
12               [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
13               public byte[] digest;
14           }
15 
16           [DllImport("cryptdll.dll")]
17           public static extern void MD5Init(ref MD5_CTX context);
18           [DllImport("cryptdll.dll")]
19           public static extern void MD5Update(ref MD5_CTX context, Byte[] input, Int32 inlen);
20           [DllImport("cryptdll.dll")]
21           public static extern void MD5Final(ref MD5_CTX context);
22 
23           MD5_CTX md5data = new MD5_CTX();
24           protected override void HashCore(byte[] array, int ibStart, int cbSize)
25           {
26               if (ibStart != 0)
27               {
28                   byte[] tmparray = new byte[cbSize - ibStart];
29                   array.CopyTo(tmparray, ibStart);
30                   array = tmparray;
31               }
32               MD5Update(ref md5data, array, cbSize);
33           }
34 
35           protected override byte[] HashFinal()
36           {
37               MD5Final(ref md5data);
38               return md5data.digest;
39           }
40 
41           public MyMD5()
42           {
43               Initialize();
44           }
45           public override void Initialize()
46           {
47               MD5Init(ref md5data);
48           }
49 
50           public byte[] ComputeHash(Stream inputStream, int offset, long count)
51           {
52               int num;
53               long totalHashCount = 0;
54 
55               byte[] buffer = new byte[0x1000];
56               do
57               {
58                   int readCount = buffer.Length;
59                   if (count - totalHashCount < buffer.Length)
60                   {
61                       readCount = (int)(count - totalHashCount);
62                   }
63                   num = inputStream.Read(buffer, 0, readCount);
64                   if (num > 0)
65                   {
66                       this.HashCore(buffer, 0, num);
67                       totalHashCount += num;
68                   }
69               }
70               while (num > 0);
71               this.HashValue = this.HashFinal();
72               byte[] buffer2 = (byte[])this.HashValue.Clone();
73               this.Initialize();
74               return buffer2;
75           }
76       }

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-610738/,如需轉載,請註明出處,否則將追究法律責任。

相關文章