C#中的哈希计算

时间:2012-07-12 15:13:01

标签: c# hash md5 abstract-class sha1

我正在为所选文件计算MD5,MD4,SHA1,SHA256,SHA512,RIPEMD160等。 我创建了以下算法,但它有问题。

        string finalHash;
        byte[] buffer;
        byte[] oldBuffer;
        int bytesRead;
        int oldBytesRead;
        long streamSize;
        long totalBytesRead = 0;
        try
        {
            if (!String.IsNullOrEmpty(selectedFile))
            {
                _dataStream = File.OpenRead(selectedFile);
                selectedFile = string.Empty;
            }
            foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)
            {
                //totalBytesRead = 0;
                streamSize = _dataStream.Length;
                buffer = new byte[4096];
                bytesRead = _dataStream.Read(buffer, 0, buffer.Length);
                totalBytesRead += bytesRead;
                do
                {
                    oldBytesRead = bytesRead;
                    oldBuffer = buffer;
                    buffer = new byte[4096];
                    bytesRead = _dataStream.Read(buffer, 0, buffer.Length);
                    totalBytesRead += bytesRead;
                    if (bytesRead == 0)
                    {
                        hashObject.TransformFinalBlock(oldBuffer, 0, oldBytesRead);
                    }
                    else
                    {
                        hashObject.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0);
                    }
                    hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100 / streamSize));
                } while (bytesRead != 0);
                e.Result = hashObject.Hash;
                finalHash = GenerateHex(hashObject.Hash);
                Invoke(new MethodInvoker(() =>
                                             {
                                                 // Get finalHash 
                                             }));
                hashObject.Dispose();
            }
        }
        catch (Exception)
        {
        }


        private HashAlgorithm HashObject
        {           
            get
            {
                if (isMD5Selected)
                {
                    _hashObject = MD5.Create();
                    isMD5Selected = false;
                }
                else if (isMD4Selected)
                {
                    _hashObject = MD4.Create();
                    isMD4Selected = false;
                }
                else if (isSHA1Selected)
                {
                    _hashObject = SHA1.Create();
                    isSHA1Selected = false;
                }
                ...
                return _hashObject;
                }
            }

在上面的代码中,foreach语句取决于所选哈希算法的数量。它会正确计算第一个选定的哈希值,但在第二个和其他每个下一次迭代时,它会给出错误的值。 怎么了。有谁能够帮我? 非常感谢。

1 个答案:

答案 0 :(得分:2)

您没有重置流,因此您可以通过循环重新读取每次迭代的内容。您的缓冲区管理逻辑可以简化很多,并且希望在hashObject.Dispose块中调用finally,以便在抛出异常时释放资源。

        streamSize = _dataStream.Length;
        buffer = new byte[4096];  
        foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)  
        {  
            try
            {
                // reset stream position, progress
                _dataStream.Position = 0;
                _totalBytesRead = 0;

                do  
                {  
                    bytesRead = _dataStream.Read(buffer, 0, buffer.Length);  
                    totalBytesRead += bytesRead;  
                    if (_dataStream.Position == _dataStream.Length)  
                    {  
                        hashObject.TransformFinalBlock(buffer, 0, bytesRead);  
                    }  
                    else  
                    {  
                        hashObject.TransformBlock(buffer, 0, bytesRead, buffer, 0);  
                    }  
                    hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100 / streamSize));  
                } while (_dataStream.Position < _dataStream.Length);  

                e.Result = hashObject.Hash;  
                finalHash = GenerateHex(hashObject.Hash);  
                Invoke(new MethodInvoker(() =>  
                                             {  
                                                 // Get finalHash   
                                             }));  
            }
            finally 
            {
                hashObject.Dispose();  
            }
        }  

如果文件不大,则提供更好的解决方案:

将流中的所有数据读入缓冲区一次,然后重新使用它可能会更高效:

        if (!String.IsNullOrEmpty(selectedFile))  
        {  
            buffer = File.ReadAllBytes(selectedFile);  
            streamSize = buffer.Length;
            selectedFile = string.Empty;  
        }  

        foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)  
        {  
            int offset = 0;
            while (buffer.Length - offset >= streamSize)
            {
                offset += hashObject.TransformBlock(buffer, offset, streamSize, buffer, offset);
                hashCalculationWorker.ReportProgress((int)((double)offset * 100 / streamSize));  
            }

            hashObject.TransformFinalBlock(buffer, offset, buffer.Length - offset);
            hashCalculationWorker.ReportProgress(100);  

            e.Result = hashObject.Hash;  
            finalHash = GenerateHex(hashObject.Hash);  
            Invoke(new MethodInvoker(() =>  
                                         {  
                                             // Get finalHash   
                                         }));  
            hashObject.Dispose();  
        }