Here's an extremely rough example of what you're trying to do. There are a lot of places where improvement could be made, but it is a working sample that you can hopefully build on.
First, we create a class that implements IDisposable. This allows us to use this class in using statements. This class will instantiate the three other objects we need, and handle disposing them, all by itself.
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
}
Now, we can use this class like so:
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();
}
}
If you run this example, you can see that it writes "Test string" to a file using the cryptostream, and then reads the same text back from that file. Checking the value of text, we can see that it is still "Test string", indicating that the procedure was successful.
{}. It is considered aesthethically correct to dousing () /* new line*/ using () /* new line */ using () {without the middle{. Visual Studio will format all theusingat the same levelusingis just syntactic sugar forIDisposables. This is what's generated from a using, to take out any magic: learn.microsoft.com/en-us/dotnet/csharp/language-reference/…. Thus, the answer is, yes, you can do this by creating aIDisposableMyDecryptionStreamthat correctly manages the usage & disposal of the underlyingFileStream,AesCryptoServiceProvider, andCryptoStream. I'd recommend you try that and come back to SO with problems you encounter while implementing theIDisposable.