【问题标题】:Decrypt file into memory解密文件到内存
【发布时间】:2019-11-22 21:32:02
【问题描述】:

我有使用 Rijnadel (AES) 解密文件的功能。 看起来像这样:

public static bool FileDecrypt(string inputFile, string outputFile, string password)
    {

        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        byte[] salt = new byte[32];

        FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
        fsCrypt.Read(salt, 0, salt.Length);

        RijndaelManaged AES = new RijndaelManaged();
        AES.KeySize = 256;
        AES.BlockSize = 128;
        var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
        AES.Key = key.GetBytes(AES.KeySize / 8);
        AES.IV = key.GetBytes(AES.BlockSize / 8);
        AES.Padding = PaddingMode.PKCS7;
        AES.Mode = CipherMode.CFB;

        CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);

        FileStream fsOut = new FileStream(outputFile, FileMode.Create);

            int read;
            byte[] buffer = new byte[1048576];

            try
            {
                while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
                    fsOut.Write(buffer, 0, read);
                }
            }
            catch (CryptographicException ex_CryptographicException)
            {
                fsOut.Close();
                fsCrypt.Close();
                LogWriter loger = new LogWriter("Cryptography error: " + ex_CryptographicException.ToString());
                return false;
            }
            catch (Exception ex)
            {
                fsOut.Close();
                fsCrypt.Close();
                LogWriter loger = new LogWriter("Exception error: " + ex.ToString());
                return false;
            }

            try
            {
                cs.Close();
            }
            catch (Exception ex)
            {
                fsCrypt.Close();
                fsOut.Close();
                LogWriter loger = new LogWriter("Error when closing Cryptostream. Error: " + ex.ToString());
                return false;
            }
            finally
            {
                fsOut.Close();
                fsCrypt.Close();
            }

    return true;


    }

它解密文件并创建新的解密文件。

但我想解密该文件并将其仅加载到内存中。大多数是 xml 配置文件,所以我想用 xmlserializer 读取 xml 配置并在我的程序中使用它,然后从内存中处理文件。那可能吗?谢谢大家的回答。

PS:不要介意在所有捕获中关闭流。由于某种原因,finally 块不起作用,仍在尝试解决。

//编辑:

这是我的尝试:

MemoryStream inMemoryCopy = new MemoryStream();

        byte[] salt = new byte[32];
        using (FileStream fs = File.OpenRead(inputfile))
        {
            fs.Read(salt, 0, salt.Length);
            fs.CopyTo(inMemoryCopy);
        }

        byte[] bytesToBeDecrypted = inMemoryCopy.ToArray();
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);


        RijndaelManaged AES = new RijndaelManaged();
        AES.KeySize = 256;
        AES.BlockSize = 128;
        var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
        AES.Key = key.GetBytes(AES.KeySize / 8);
        AES.IV = key.GetBytes(AES.BlockSize / 8);
        AES.Padding = PaddingMode.PKCS7;
        AES.Mode = CipherMode.CFB;

        CryptoStream cs = new CryptoStream(bytesToBeDecrypted, AES.CreateDecryptor(), CryptoStreamMode.Read);

问题是我不能在加密流中使用字节数组。即使没有文件流,我还能以某种方式做到这一点吗?

【问题讨论】:

  • 使用 MemoryStream 而不是 FileStream。
  • @Dbuggy 然后我可以像处理普通文件一样使用它吗?这就是我的观点,因为直到现在才需要它。从未使用过内存中的对象。如果我做对了:我只是做同样的功能,只是将文件流更改为内存流?但是当我在某个地方调用它时,我怎么知道内存中的对象在哪里?

标签: c# wpf cryptography


【解决方案1】:

您想像这样使用 XmlSerializer 从流中获取一些配置对象。源流是 FileStream、NetworkStream 还是 CryptoStream 本身都没有关系。所以不需要使用字节缓冲区。

请注意,以下代码改编自您的代码。我从中剥离了 try catch,只显示了反序列化所需的核心代码。

public SomeConfig ReadEncryptedConfiguration(string inputFile, string password)
{
    using (var stream = CreateStream(inputFile, password))
    {
        var ser = new XmlSerializer(typeof(SomeConfig));
        var config = (SomeConfig) ser.Deserialize(stream);
        return config;
    }
}

CreateStream 方法将制作上一部分中使用和处理的流。我使用了另一个构造函数来确保在释放 CryptoStream 时释放底层文件流。

public CryptoStream CreateStream(string inputFile, string password)
{
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
    byte[] salt = new byte[32];

    FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
    fsCrypt.Read(salt, 0, salt.Length);

    RijndaelManaged AES = new RijndaelManaged();
    AES.KeySize = 256;
    AES.BlockSize = 128;
    var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
    AES.Key = key.GetBytes(AES.KeySize / 8);
    AES.IV = key.GetBytes(AES.BlockSize / 8);
    AES.Padding = PaddingMode.PKCS7;
    AES.Mode = CipherMode.CFB;

    return new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read, false);
}

【讨论】:

  • 我想当我想像这样返回配置时需要使用 cast 吗?
  • 啊,是的,在反序列化时你需要转换为 SomeConfig.. 我不测试代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-19
  • 2017-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
相关资源
最近更新 更多