Заменить вложенный оператор using одним оператором using - PullRequest
0 голосов
/ 08 июня 2018

Я повторяю себя с этим кодом

using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)
{
  using (var aes = AesCryptoServiceProvider() { Key = ... }
  {

    // Read the IV at the beginning of the filestream

    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read)
    {

      // Actual code only using cryptoStream

    }
  }
}

и

using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
  using (var aes = AesCryptoServiceProvider() { Key = ... }
  {

    // Write the IV at the beginning of the filestream

    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Write)
    {

      // Actual code only using cryptoStream

    }
  }
}

И я спрашиваю себя, можно ли заменить это на что-то подобное

using (var cryptoStream = new MyDecryptionStream(path))
{
  // Actual code
}

Фактический код может сильно отличаться.Это может быть изображение, которое необходимо сохранить, или сериализация в формате XML.

Я попытался реализовать свой собственный класс Stream, который приводит все методы к частному свойству CryptoStream.Но это не сработало.Это всегда ломалось у коллеги, где я пытался прочитать IV в начале.

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

А как насчет вспомогательной функции?

public static TResult ReadFileUsingCrypto<TResult>(string path, KeyThing key, Func<CryptoStream, TResult> use)
{
    using (var fileStream = new FileStream(path, FileMode.Open, FileAccesa.Read))
    using (var aes = new AesCryptoServiceProvider(){...}))
    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
    {
        return use(cryptoStream);
    }
}

А потом

var result = ReadFileUsingCrypto(“myFile”, key, crypto => <use crypto here and return result>);
0 голосов
/ 08 июня 2018

Вот чрезвычайно грубый пример того, что вы пытаетесь сделать.Есть много мест, где можно сделать улучшения, но это рабочий пример, на котором можно надеяться построить.

Сначала мы создадим класс, который реализует IDisposable.Это позволяет нам использовать этот класс в using инструкциях.Этот класс будет создавать экземпляры трех других нужных нам объектов и обрабатывать их удаление самостоятельно.

class MyCryptoStream : IDisposable
{
    private FileStream fileStream = null;
    private AesCryptoServiceProvider aes = null;
    public CryptoStream cryptoStream = null;

    public enum Mode
    {
        Write,
        Read
    }

    public MyCryptoStream(string filepath, Mode mode, byte[] key, byte[] iv = null)
    {
        if(mode == Mode.Write)
        {
            fileStream = new FileStream(filepath, FileMode.Open, FileAccess.Write);
            fileStream.Write(iv, 0, 16);
            aes = new AesCryptoServiceProvider() { Key = key, IV = iv };

            cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
        }
        else
        {
            iv = new byte[16];
            fileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read);
            fileStream.Read(iv, 0, 16);
            aes = new AesCryptoServiceProvider() { Key = key, IV = iv };

            cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
        }
    }

    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                if (cryptoStream != null)
                {
                    cryptoStream.Dispose();
                }
                if (aes != null)
                {
                    aes.Dispose();
                }
                if (fileStream != null)
                {
                    fileStream.Dispose();
                }
            }

            // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
            // TODO: set large fields to null.

            disposedValue = true;
        }
    }

    // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
    // ~UsingReduction() {
    //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    //   Dispose(false);
    // }

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion

}

Теперь мы можем использовать этот класс следующим образом:

        string path = "..\\..\\test.txt";
        byte[] key = null;
        byte[] iv = null;
        using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
        {
            key = myAes.Key;
            iv = myAes.IV;
        }
        using (MyCryptoStream ur = new MyCryptoStream(path, MyCryptoStream.Mode.Write, key, iv))
        {
            using (StreamWriter sw = new StreamWriter(ur.cryptoStream))
            {
                sw.Write("Test string");
            }
        }
        string text = string.Empty;
        using (MyCryptoStream ur = new MyCryptoStream(path, MyCryptoStream.Mode.Read, key))
        {
            using (StreamReader sr = new StreamReader(ur.cryptoStream))
            {
                text = sr.ReadToEnd();
            }
        }

Если вызапустив этот пример, вы увидите, что он записывает "Test string" в файл, используя cryptostream, а затем считывает тот же текст обратно из этого файла.Проверяя значение text, мы видим, что оно все еще равно "Test string", что указывает на успешность процедуры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...