C# "Bad Data" exception when decrypting encrypted file

Raphael picture Raphael · Apr 8, 2011 · Viewed 11.2k times · Source

Hey I'm very new to encryption and decryption, or even the c# language to be honest. Basically, I have a tcp chat server that "saves" logs and encrypts the text file. This is how I encrypt (based from the MSDN sample):

public static void EncryptFile(string strInputFileName, string strOutputFileName, string strKey)
{
    FileStream fsIn = new FileStream(strInputFileName, FileMode.Open, FileAccess.Read);
    FileStream fsOut = new FileStream(strOutputFileName, FileMode.Create, FileAccess.Write);

    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    des.Key = ASCIIEncoding.ASCII.GetBytes(strKey);
    des.IV = ASCIIEncoding.ASCII.GetBytes(strKey);


    ICryptoTransform desencrypt = des.CreateEncryptor();
    CryptoStream cryptostream = new CryptoStream(fsOut, desencrypt, CryptoStreamMode.Write);

    byte[] byteArrayInput = new byte[fsIn.Length - 1];
    fsIn.Read(byteArrayInput, 0, byteArrayInput.Length);
    cryptostream.Write(byteArrayInput, 0, byteArrayInput.Length);

    fsIn.Close();
    fsOut.Close();
}

The method success fully encrypts files. This is my decrypt method:

public static void DecryptFile(string strInputFileName, string strOutputFileName, string strKey)
{
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    des.Key = ASCIIEncoding.ASCII.GetBytes(strKey);
    des.IV = ASCIIEncoding.ASCII.GetBytes(strKey);

    byte[] te = new byte[1024];
    FileStream fsRead = new FileStream(strInputFileName, FileMode.Open, FileAccess.Read);
    ICryptoTransform desdecrypt = des.CreateDecryptor();          

    CryptoStream cryptostream = new CryptoStream(fsRead, desdecrypt, CryptoStreamMode.Read);
    StreamWriter fsDecrypted = new StreamWriter(strOutputFileName);            

    fsDecrypted.Write(new StreamReader(cryptostream).ReadToEnd());//This is where the "Bad Data" occurs.
    fsDecrypted.Flush();
    fsDecrypted.Close();
    fsRead.Close();
}

And when I inspect the cryptostream object, it says that it has thrown an exception, "Stream does not support seeking".

Any help would be greatly appreciated!

Answer

Jon Skeet picture Jon Skeet · Apr 8, 2011

Here:

    cryptostream.Write(byteArrayInput, 0, byteArrayInput.Length);
    fsIn.Close();
    fsOut.Close();

You're closing fsOut directly, without closing cryptostream. That means the crypto stream doesn't get the chance to flush any final blocks etc.

Additionally:

  • Use using statements instead of manually calling Close or Dispose
  • You're currently calling Read once, and assuming it will read all the data - you're not checking the return value. (You're also removing the last byte of the input file for some reason... why?) In general, you should loop round, reading into a buffer and then writing out however many bytes you read, until the Read method returns 0. If you're using .NET 4, Stream.CopyTo is your friend.