在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               inputStream.Seek(offset,SeekOrgin.Begin);//感谢denworld指正
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       }
posted on 2009-07-28 17:38  aaaSoft  阅读(1871)  评论(4编辑  收藏  举报