How can i add a progress bar on a cryptostream write operation in c#

1.1k Views Asked by At

I have been working on a program to encrypt and decrypt a file as part of a project. The program is working fine on its own but when I try to add a progress bar to it to show the progress of the encryption/decryption process things go wrong. The progress bar proceeds pretty good upto around 85-90% and then it throws an error that the value has exceeded the maximum limit. Also the bar proceeds too slow, it takes around 15-20 seconds to reach the error situation even when I am encrypting a 16KB file, which takes almost no time when done without any progress bar. I have tried using a backgroundworker to implement the progressbar. Can anyone can tell me how I can get the progressbar to work on my program?

Here is my code for the encryption process:

public void EncryptFile()
    {

        try
        {
            OpenFileDialog od = new OpenFileDialog();
            od.Title = "Select File To Encrypt";
            od.Filter = "All files (*.*)|*.*";
            string ifile = "";
            if (od.ShowDialog() == DialogResult.OK)
            {
                ifile = od.InitialDirectory + od.FileName;
            }
            else
            {
                MessageBox.Show("No file selected!!");
                goto b;
            }

            if (Path.GetExtension(ifile) == ".arv")
            {
                MessageBox.Show("Error!!File already Encrypted.");
                return;
            }
            string ofile = ifile + ".arv";

        a: string password = Prompt.ShowDialog();
            if (password == "")
            {
                MessageBox.Show("Password Field cannot be blank!!");
                goto a;
            }
            else if (password == null)
            {
                goto b;
            }
            int ph = password.GetHashCode();
            byte[] ia = BitConverter.GetBytes(ph);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(ia);
            byte[] phb = ia;

            UnicodeEncoding UE = new UnicodeEncoding();
            byte[] salt = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80 };
            Rfc2898DeriveBytes k = new Rfc2898DeriveBytes(password, salt);

            string cryptFile = ofile;
            FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);

            AesManaged AMCrypto = new AesManaged();
            AMCrypto.Key = k.GetBytes(32);
            AMCrypto.IV = k.GetBytes(16);

            CryptoStream cs = new CryptoStream(fsCrypt, AMCrypto.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(phb, 0, 4);
            FileStream fsIn = new FileStream(ifile, FileMode.Open);

            int data;
            while ((data = fsIn.ReadByte()) != -1)
                cs.WriteByte((byte)data);

            fsIn.Close();
            cs.Close();
            fsCrypt.Close();
            File.Delete(ifile);
            MessageBox.Show("File Encrypted!!");
        b: ;
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
        }

The Prompt is a separate class that I created to generate a dynamic form that asks the user to enter his password. It looks pretty much like any password prompt with two fields to enter and verify the password and a show password checkbox. The ifile is the input file while ofile is the output file.

Update: Here is the code that I tried with backgroundworker. The progress bar seems to work now but the encryption speed is reduced considerably and also the encryption process completes before the progress bar is filled,i.e., the "encryption complete" message shows up before the progress bar has filled. Also when I try to do the same thing for decryption i get an exception saying that the cryptostream does not support seeking. Any ideas?

public Form1()
    {
        InitializeComponent();
        Shown += new EventHandler(Form1_Shown);


        backgroundWorker1.WorkerReportsProgress = true;

        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);

        backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
    }
    void Form1_Shown(object sender, EventArgs e)
    {

        backgroundWorker1.RunWorkerAsync();
    }
    void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {

            string ifile = @"F:\abc.mp4";
            int i = 0;
            if (Path.GetExtension(ifile) == ".arv")
            {
                MessageBox.Show("Error!!File already Encrypted.");
                return;
            }
            string ofile = ifile + ".arv";

        a: string password = Prompt.ShowDialog();
            if (password == "")
            {
                MessageBox.Show("Password Field cannot be blank!!");
                goto a;
            }
            else if (password == null)
            {
                goto b;
            }
            int ph = password.GetHashCode();
            byte[] ia = BitConverter.GetBytes(ph);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(ia);
            byte[] phb = ia;

            UnicodeEncoding UE = new UnicodeEncoding();
            byte[] salt = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80 };
            Rfc2898DeriveBytes k = new Rfc2898DeriveBytes(password, salt);

            string cryptFile = ofile;
            FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);

            AesManaged AMCrypto = new AesManaged();
            AMCrypto.Key = k.GetBytes(32);
            AMCrypto.IV = k.GetBytes(16);

            CryptoStream cs = new CryptoStream(fsCrypt, AMCrypto.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(phb, 0, 4);
            FileStream fsIn = new FileStream(ifile, FileMode.Open);

            int data;
            double counter = 1;
            while ((data = fsIn.ReadByte()) != -1)
            {
                cs.WriteByte((byte)data);
                backgroundWorker1.ReportProgress((int)((counter / fsIn.Length) * 100));
                counter++;
            }

            fsIn.Close();
            cs.Close();
            fsCrypt.Close();
            File.Delete(ifile);
            MessageBox.Show("File Encrypted!!");
        b: ;
        }
        catch (Exception f)
        {
            MessageBox.Show(f.ToString());
        }
1

There are 1 best solutions below

1
On

Using a BackgroundWorker:

int data;
double counter = 1;
while ((data = fsIn.ReadByte()) != -1)
{
    cs.WriteByte((byte)data);
    worker.ReportProgress((int)((counter / fs.Length) * 100));
    counter++;
}

If you are unsure on how to use a BackgroundWorker:

C# Progress bar - can't wrap my head around it