1
votes

I am working on calculation of MD5, MD4, SHA1, SHA256, SHA512, RIPEMD160 etc. for selected file. I have created the following algorithm but it has problem.

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

In the above code, foreach statement depends on number of selected hash algorithms. It calculates first selected hash correctly but on the second and other every next iteration it gives wrong values. Whats wrong. Can anybody help me? Thanks a lot in advance.

1
On first glance, you're not resetting your _dataStream...lc.
Off the top of my head, you aren't resetting your variables and datastream correctly.KingCronus
@KingCronus Is it necessary to get _dataStream on each iteration?NASSER
On resetting _dataStream it takes too much time int next iterations.NASSER
@Ic Is it necessary to get _dataStream on each iteration? On resetting _dataStream it takes too much time int next iterations. I have checked it. It is working fine when I use it without foreach statement repeatedly.NASSER

1 Answers

2
votes

You are not resetting the stream so that you can re-read its contents for each iteration through the loop. Your buffer management logic can be simplified quite a bit, and it would be desireable to call hashObject.Dispose in a finally block so resources are released in case an exception is thrown.

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

Better solution if the files are not large:

It may be more performant to read all of the data from the stream into a buffer once, and then re-use it:

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