0


I'm writing a web application which allows users to upload files and download files. Files like doc, or jpeg are allowed. The files are encrypted in uploading process and decrypted in downloading process.
I use AES as the algorithm, with one key for all files, but different salt for each file. I also make sure both encryption and decryption method use the same key and padding method.
However, when the website tries to decrypt a file, it creates a corrupted file which has a bigger size then the original file.
So I'm not sure if the encryption or decryption process messes up the file.
Here is the source code:

    //Encryption method
    private bool SaveEnryptFile(FileUpload fileUp)
        {
            try
            {
                string fName = fileUp.PostedFile.FileName;
                string outputDir = Path.Combine(ConfigurationManager.AppSettings["clientDocFolder"] + CurrentUser.Name);
                DirectoryInfo di = new DirectoryInfo(outputDir);
                di.Create();
                string outputFile = Path.Combine(outputDir, fName);
                if (File.Exists(outputFile))
                {
                    throw new Exception("File already exists");
                }
                else
                {
                    byte[] file = new byte[fileUp.PostedFile.ContentLength];
                    fileUp.PostedFile.InputStream.Read(file, 0, fileUp.PostedFile.ContentLength);
//get the key string from web.config
                    var key = ConfigurationManager.AppSettings["keyFile"];
//randomly create a salt
                    byte[] salt = new byte[8];
                    var rng = new RNGCryptoServiceProvider();
                    rng.GetBytes(salt);
                    var derivedBytes = new Rfc2898DeriveBytes(key, salt);
                    using (AesCryptoServiceProvider alg = new AesCryptoServiceProvider())
                    {
                        alg.Key = derivedBytes.GetBytes(alg.KeySize / 8);
                        alg.IV = derivedBytes.GetBytes(alg.BlockSize / 8);
                        alg.Padding = PaddingMode.Zeros;
                        // Create a decrytor to perform the stream transform.
                        using (ICryptoTransform encryptor = alg.CreateEncryptor())
                        {
                            using (var fs = File.Create(outputFile))
                            {
//store the salt in the encrypted file
                                fs.Write(salt, 0, 8);
//write encrypted bytes to encrypted file
                                using (CryptoStream cs = new CryptoStream(fs, encryptor, CryptoStreamMode.Write))
                                {
                                    cs.Write(file, 0, file.Length);
                                    cs.FlushFinalBlock();
                                }
                            }
                        }
                    }
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

//Decryption method:

var path = Path.Combine(ConfigurationManager.AppSettings["clientDocFolder"] + CurrentUser.Name + "\\" + ((WebControl)sender).Attributes["DocumentID"]);
                    if (File.Exists(path))
                    {
                        using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                        {
//Get the salt from the encrypted file
                            byte[] salt = new byte[8];
                            fs.Read(salt, 0, salt.Length);
//get key string from web.config file
                            string key = ConfigurationManager.AppSettings["keyFile"];
                            var derivedBytes = new Rfc2898DeriveBytes(key, salt);
                            AesCryptoServiceProvider alg = new AesCryptoServiceProvider();
                            alg.Key = derivedBytes.GetBytes(alg.KeySize / 8);
                            alg.IV = derivedBytes.GetBytes(alg.BlockSize / 8);
                            alg.Padding = PaddingMode.Zeros;
                            using (ICryptoTransform decryptor = alg.CreateDecryptor())
                            {
//byte array to store encrypted bytes.
//I use fs.Length-8 because first 8 bytes were used to store salt
                                byte[] encryptedBytes = new byte[fs.Length - 8];
                                int encryptedByteCnt = fs.Read(encryptedBytes, 0, encryptedBytes.Length);

                                using (MemoryStream ms = new MemoryStream(encryptedBytes))
                                {
                                    byte[] plainBytes = new byte[encryptedByteCnt];
                                    using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                                    {
//decrypt encrypted bytes into a byte array
                                        int decryptedByteCnt = cs.Read(plainBytes, 0, plainBytes.Length);
                                    }
//Write decrypted bytes in response stream
                                    Response.ContentType = "application/octet-stream";
                                    Response.AddHeader("content-disposition", "attachment; filename=" + Path.GetFileName(path));
                                    Response.OutputStream.Write(plainBytes, 0, plainBytes.Length);
                                    Response.Flush();
                                }
                            }
                        }
                    }
                    else
                    {
                        ScriptManager.RegisterStartupScript(this, this.GetType(), "DownloadDocument", "alert('" + String.Format("There is no file such as {0} exists. Please contact us if you face this problem.);", ((WebControl)sender).Attributes["DocumentID"]) + "'", true);
                        return;
                    }
  • If I may Ask, What is the reason for encrypting and decryption the file in the first place if you are saving the file to the server itself? – Anup Sharma Jan 08 '16 at 17:20
  • hi, i already did the normal upload/download process. Now I just want to add a bit extra security to the website. – Tùng Trịnh Jan 08 '16 at 17:24
  • Debug: Use a small test file, perhaps 40 bytes. Hex dump before and after encryption, before and after decryption. Then see if you can determine where the problem is. If that doesn't let you determine the problem add that hex dumps to the question. – zaph Jan 08 '16 at 17:25
  • @TùngTrịnh Not to be nosy here but the files are going to be un-encrypted when you send to or receive from client. And file is being saved on the same web server where you have kept the key. I don't really see any thing secure in this – Anup Sharma Jan 08 '16 at 17:28
  • @AnupSharma the encryption increases the work factor to more than drive-by browsing of the files. It is possible the key is in a secure device. I hear ofter the complaint that the exposed data was not encrypted yer here encryption is being dismissed. – zaph Jan 08 '16 at 17:31
  • @zaph thanks for the suggestion. I tested with a txt file and when i opened the dowloaded file, the file is in html format which contains basically the html page. Any thought? – Tùng Trịnh Jan 08 '16 at 17:38
  • @AnupSharma it is to make sure someone have access to the folder on the server side can't open the file. – Tùng Trịnh Jan 08 '16 at 17:39
  • Encrypted data is not text, it is a series of 8-bit bytes that are indistinguishable from random bytes. They are not fully displayable as text. Thus a hex display is needed and in order to be text are usually converted (encoded) to hexadecimal or Base64. It seems in your case you are not encrypting/decrypting sending what you think you are. – zaph Jan 08 '16 at 17:43
  • @zaph: I think in my code i already convert the source file into an array of bytes. Could you let me know what is encrypted base on my code if I have a file C:\test.txt – Tùng Trịnh Jan 08 '16 at 17:47
  • @zaph: I got hex 00-00-00-00. Not sure why the fileupload doest read any byte into the array. – Tùng Trịnh Jan 08 '16 at 17:50
  • 1
    So it seems not an encryption problem but a http problem. – zaph Jan 08 '16 at 17:53

1 Answers1

0

It turned out the problem is with the http posted file. That causes the input bytes are not read to the array. It ended up that I need to set the position of the stream before it reads to 0.
So I changed the code a little bit in the encryption method like below:
From

byte[] file = new byte[fileUp.PostedFile.ContentLength];
                fileUp.PostedFile.InputStream.Read(file, 0, fileUp.PostedFile.ContentLength);

To:

byte[] file = new byte[fileUp.PostedFile.ContentLength];
Stream st = fileUp.FileContent;
st.Position = 0;
st.Read(file, 0, file.Length);
st.Close();

However, I ran to the problem with decryption. It will adds extra bytes in the decrypted byte array. Most of them are 0.

Updated: I change the writing decrypted so it won't write trailing zeros. But now the downloaded file sent from the server will contain the html of the page itself.