Расшифровка AesCryptoServiceProvider создает поврежденный файл


Я пишу веб-приложение, которое позволяет пользователям загружать файлы и скачивать файлы. Файлы типа doc или jpeg разрешены. Файлы шифруются в процессе загрузки и расшифровываются в процессе загрузки.
В качестве алгоритма я использую AES с одним ключом для всех файлов, но с разной солью для каждого файла. Я также удостоверяюсь, что и для шифрования, и для дешифрования используется один и тот же ключ и метод заполнения.
Однако, когда веб-сайт пытается расшифровать файл, он создает поврежденный файл, который имеет больший размер, чем исходный файл.
Поэтому я не уверен, что процесс шифрования или дешифрования испортил файл.
Вот исходный код:

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

//Метод расшифровки:

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

person Tùng Trịnh    schedule 08.01.2016    source источник
comment
Если я могу спросить, в чем причина для шифрования и дешифрования файла в первую очередь, если вы сохраняете файл на самом сервере?   -  person Anup Sharma    schedule 08.01.2016
comment
привет, я уже сделал обычный процесс загрузки/выгрузки. Теперь я просто хочу добавить немного дополнительной безопасности на сайт.   -  person Tùng Trịnh    schedule 08.01.2016
comment
Отладка: используйте небольшой тестовый файл, возможно, 40 байт. Hex дамп до и после шифрования, до и после расшифровки. Затем посмотрите, сможете ли вы определить, где проблема. Если это не позволяет определить проблему, добавьте к вопросу шестнадцатеричные дампы.   -  person zaph    schedule 08.01.2016
comment
@TùngTrịnh Не хочу быть любопытным, но файлы будут незашифрованными, когда вы отправляете или получаете от клиента. И файл сохраняется на том же веб-сервере, где вы сохранили ключ. Я действительно не вижу ничего безопасного в этом   -  person Anup Sharma    schedule 08.01.2016
comment
@AnupSharma, шифрование увеличивает коэффициент работы больше, чем просто просмотр файлов. Возможно, ключ находится в защищенном устройстве. Я часто слышу жалобы на то, что раскрытые данные не были зашифрованы, здесь шифрование отклоняется.   -  person zaph    schedule 08.01.2016
comment
@zaph спасибо за предложение. Я протестировал файл txt, и когда я открыл загруженный файл, файл был в формате html, который содержит в основном html-страницу. Любая мысль?   -  person Tùng Trịnh    schedule 08.01.2016
comment
@AnupSharma, чтобы убедиться, что кто-то, имеющий доступ к папке на стороне сервера, не может открыть файл.   -  person Tùng Trịnh    schedule 08.01.2016
comment
Зашифрованные данные — это не текст, это последовательность 8-битных байтов, неотличимых от случайных байтов. Они не полностью отображаются как текст. Таким образом, требуется шестнадцатеричный дисплей, и для того, чтобы текст был обычно преобразован (закодирован) в шестнадцатеричный или Base64. Кажется, в вашем случае вы не шифруете/дешифруете отправку того, что вы думаете.   -  person zaph    schedule 08.01.2016
comment
@zaph: я думаю, что в своем коде я уже преобразовал исходный файл в массив байтов. Не могли бы вы сообщить мне, что зашифровано на основе моего кода, если у меня есть файл C:\test.txt   -  person Tùng Trịnh    schedule 08.01.2016
comment
@zaph: я получил шестнадцатеричный код 00-00-00-00. Не уверен, почему загрузка файла не считывает ни одного байта в массив.   -  person Tùng Trịnh    schedule 08.01.2016
comment
Так что это не проблема с шифрованием, а проблема с http.   -  person zaph    schedule 08.01.2016


Ответы (1)


Оказалось проблема с выложенным http файлом. Это приводит к тому, что входные байты не считываются в массив. В итоге мне нужно установить позицию потока до того, как он будет прочитан до 0.
Поэтому я немного изменил код в методе шифрования, как показано ниже:
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();

Однако столкнулся с проблемой с расшифровкой. Это добавит дополнительные байты в расшифрованный массив байтов. Большинство из них 0.

Обновлено: я изменяю расшифрованную запись, чтобы она не записывала конечные нули. Но теперь загруженный файл, отправленный с сервера, будет содержать html самой страницы.

person Tùng Trịnh    schedule 08.01.2016