【问题标题】:AesCryptoServiceProvider decrypt creates corrupted fileAesCryptoServiceProvider 解密创建损坏的文件
【发布时间】:2016-01-08 17:14:10
【问题描述】:


我正在编写一个允许用户上传文件和下载文件的网络应用程序。允许使用 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;
                    }

【问题讨论】:

  • 如果我可以问,如果您将文件保存到服务器本身,首先加密和解密文件的原因是什么?
  • 嗨,我已经完成了正常的上传/下载过程。现在我只想为网站增加一点额外的安全性。
  • 调试:使用一个小的测试文件,大概 40 字节。加密前后、解密前后的十六进制转储。然后看看你能不能确定问题出在哪里。如果这不能让您确定问题,请将十六进制转储添加到问题中。
  • @TùngTrịnh 不要在这里多管闲事,但是当您向客户端发送或从客户端接收文件时,这些文件将是未加密的。并且文件被保存在您保存密钥的同一 Web 服务器上。我真的没有看到任何安全的东西
  • 看来不是加密问题,而是http问题。

标签: c# encryption salt aescryptoserviceprovider


【解决方案1】:

原来问题出在 http 发布的文件上。这会导致输入字节不会被读取到数组中。 结果是我需要在读取到 0 之前设置流的位置。
所以我在加密方法中稍微更改了代码,如下所示:
来自

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

收件人:

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

但是,我遇到了解密问题。它将在解密的字节数组中添加额外的字节。大多数是 0。

更新:我更改了解密的写入,因此它不会写入尾随零。但是现在从服务器发送的下载文件将包含页面本身的html。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多