C#中的哈希计算



我正在为所选文件计算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语句取决于所选哈希算法的数量。它正确地计算了第一个选定的哈希,但在第二个和其他每个下一次迭代中,它给出了错误的值。怎么了。有人能帮我吗?提前非常感谢。

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

        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();  
        }  

最新更新