Encrypting really large files with progress

I have a nice working encryption class that uses the RijndaelManaged class to encrypt a string or even a byte array. I can even use it to encrypt files fairly easily. What I'd like to do though is have a way of providing progress updates when encrypting very large files instead of the program just hanging there until it's finished. How do I do that?
LVL 22
Russ SuterSenior Software DeveloperAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Kyle AbrahamsSenior .Net DeveloperCommented:
Some code or pseudo code would be nice.

Essentially though you're going to need to get the full size of the file.
Then keep track of how much you processed.

I would store that in your class as a complete %.

From there you can do 2 things:

1)  Have an event in your class and raise that event when you update the progress (say every X% or every X seconds).  From there the calling application would subscribe to that event.

2)  or you can setup a poller in your calling application which just monitors the %completed.
Russ SuterSenior Software DeveloperAuthor Commented:
I know essentially how to do it. I just need help figuring out how to encrypt the file in chunks rather than as a single large byte array. How do I ensure that the file is properly encrypted and how do I fire the event listener?
Kyle AbrahamsSenior .Net DeveloperCommented:
This demonstrates how to raise your own event:
https://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx

You essentially need your own Delegate:

//changed from the link for your review
public delegate void ChangedEventHandler(decimal Pct);

//Inside your class you create an instance of the delegate:
 public event ChangedEventHandler Changed;

//implement the handler:
  protected void OnChanged(decimal Pct) 
      {
         if (Changed != null)
            Changed(Pct);
      }

//in your encrypt function:
OnChanged(current / total * 100);

Open in new window


Found this online for chunking, but it should work.  Essentially keep track of the current start pointer, then process that chunk, finally set start pointer to end + 1.  

const int chunkSize = 1024; // read the file by chunks of 1KB  This should be increased for performance, maybe 100MB?

using (var file = File.OpenRead("foo.dat"))
{
    int bytesRead;
    var buffer = new byte[chunkSize];
    while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0)
    {
        // TODO: Process bytesRead number of bytes from the buffer
        // not the entire buffer as the size of the buffer is 1KB
        // whereas the actual number of bytes that are read are 
        // stored in the bytesRead integer.

     //raise OnChanged?
    }
}

Open in new window

Learn SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

Russ SuterSenior Software DeveloperAuthor Commented:
OK, pseudo code...

using (FileStream inputStream = new FileStream(inputFile, FileMode.Open))
{
using (FileStream outputStream = new FileStream(outputFile, FileMode.Create))
{
                using (RijndaelManaged cipher = new RijndaelManaged())
                {
                    cipher.KeySize = 256;
                    cipher.BlockSize = 128;

                    Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, 8);
                    cipher.Key = key.GetBytes(cipher.KeySize / 8);
                    cipher.IV = key.GetBytes(cipher.BlockSize / 8);
                    cipher.Mode = CipherMode.CBC;

                    using (CryptoStream cStream = new CryptoStream(outputStream, cipher.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cStream.Write(inputStream, 0, data.Length);
                        cStream.FlushFinalBlock();
                        cStream.Close();
                    }
                }
}
}

Open in new window


Now, please help me convert that code so that it will read the file in, say, 4k chunks and provide an update every time it reads a chunk.
Russ SuterSenior Software DeveloperAuthor Commented:
I was able to create a working solution from the following 2 examples.

http://stackoverflow.com/questions/3351285/using-rijndael-encryption-for-large-files
http://www.csharp-examples.net/create-asynchronous-method/

This allows for asynchronous operation and also eliminates the potential issue of running out of memory due to allocating a large MemoryStream.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Russ SuterSenior Software DeveloperAuthor Commented:
The other comments posted offered no direction, only general advice which was already known.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.