0

I'm getting the following warning in the following code snippet but I cannot understand why

warning CA2202: Microsoft.Usage : Object 'memStream' can be disposed more than once in method 'Encrypt(string)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.

Code:

string Encrypt(string toEncrypt)
{
    byte[] key = ...
    byte[] iv = ...

    using (AesCng aes = new AesCng())
    using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
    using (MemoryStream memStream = new MemoryStream())
    using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
    {
        UTF7Encoding encoder = new UTF7Encoding();
        byte[] bytes = encoder.GetBytes(toEncrypt);

        cryptoStream.Write(bytes, 0, bytes.Length);
        cryptoStream.FlushFinalBlock();

        return Convert.ToBase64String(memStream.ToArray());
    }
}

The CryptoStream object, to the best of my knowledge, does not dispose of the passed in Stream when it itself is disposed. So how is it possible that the variable memStream can be disposed of more than once?

Many thanks.

Richardissimo
  • 5,596
  • 2
  • 18
  • 36
Ben Adelson
  • 33
  • 1
  • 4
  • 1
    I am not 100%, but I think you're not supposed to call `FlushFinalBlock()` inside the block, the using should take care of that I _think_ – maccettura Nov 27 '18 at 20:31
  • That was Raymond Chen's "Old New Thing" yesterday: https://blogs.msdn.microsoft.com/oldnewthing/20181126-00/?p=100325. Not your case, exactly, but... The Stream APIs are notorious for IDisposable weirdnesses – Flydog57 Nov 27 '18 at 20:34
  • Check the last parameter of https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream.-ctor?view=netframework-4.7.2#System_Security_Cryptography_CryptoStream__ctor_System_IO_Stream_System_Security_Cryptography_ICryptoTransform_System_Security_Cryptography_CryptoStreamMode_System_Boolean_ - https://stackoverflow.com/a/50878853/34092 (ignore the other answers, read the specific answer I linked to). – mjwills Nov 27 '18 at 20:40

2 Answers2

2

CryptoStream.Dispose() will, by default, dispose the underlying stream. If you don't want that behavior you need to use the constructor overload that explicitly makes the underlying stream remain open when the CryptoStream is disposed.

You can see how that's implemented here.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • Ahh thanks... I looked into this and didn't realize `Close` was equivalent to `Dispose` for streams – Ben Adelson Nov 27 '18 at 20:38
  • I assume you meant to link to https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream.-ctor?view=netframework-4.7.2#System_Security_Cryptography_CryptoStream__ctor_System_IO_Stream_System_Security_Cryptography_ICryptoTransform_System_Security_Cryptography_CryptoStreamMode_System_Boolean_ rather than `Dispose`? I suspect your original suggestion won't compile. – mjwills Nov 27 '18 at 20:39
-1

You can use overloaded CryptoStream constructor with leaveOpen parameter.

And no need this because CryptoStream object in using block

cryptoStream.FlushFinalBlock();

Code:

string Encrypt(string toEncrypt)
{
    byte[] key = ...
    byte[] iv = ...

    using (AesCng aes = new AesCng())
    using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
    using (MemoryStream memStream = new MemoryStream())
    using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write,true))
    {
        UTF7Encoding encoder = new UTF7Encoding();
        byte[] bytes = encoder.GetBytes(toEncrypt);

        cryptoStream.Write(bytes, 0, bytes.Length);

        return Convert.ToBase64String(memStream.ToArray());
    }
}

leaveOpen: true to not close the underlying stream when the CryptoStream object is disposed

CryptoStream ctor

furkanhb
  • 9
  • 4
  • 1
    Also consider remove the `FlushFinalBlock` and moving the return outside of the `using` block (to make the code more concise). – mjwills Nov 27 '18 at 20:45
  • You may want to read my comment again. Especially the second part of the sentence. – mjwills Nov 27 '18 at 21:06