Groups | Blog | Home
all groups > dotnet clr > november 2005 >

dotnet clr : CryptoStream.Dispose closes target stream in 2.0


Harold Howe
11/22/2005 6:15:37 PM
In .net 2.0, the dispose method of CryptoStream calls the Close method
on the destination stream (verified with .NET reflector). In 1.1, it did
not. In my opinion, the 1.1 behavior was preferable. After all, once I
am done decrypting the data, I may want to look at it. Why should I have
to keep the CryptoStream around for that purpose?

Here is an example. This routine works in .net 1.1, but fails in 2.0.

static public string DecryptString(string s, byte[] key, byte[] iv ,
SymmetricAlgorithm encryption_algorithm)
{
using(MemoryStream msout = new MemoryStream())
{
byte[] data = Convert.FromBase64String(s);
using(CryptoStream crypto = new CryptoStream(msout,
encryption_algorithm.CreateDecryptor(key,iv),
CryptoStreamMode.Write))
{
crypto .Write(data,0,data.Length);
crypto .FlushFinalBlock();
} // dispose of the cryptostream, we don't need it anymore

msout.Position = 0;
data = new byte[msout.Length];
msout.Read(data, 0, data.Length);

return System.Text.Encoding.UTF8.GetString(data,0, data.Length);
}
}

In 2.0, the memorystream is closed when the cryptostream is disposed by
the inner using statement. It is straightforward to refactor this so the
cryptostream lives as long as the memory stream, but that seems
fundamentally wrong from a resource management standpoint.

Jon Skeet [C# MVP]
11/23/2005 7:25:56 AM
[quoted text, click to view]

<snip>

[quoted text, click to view]

CryptoStream.Dispose was broken in 1.1 in that it didn't close the
CryptoStream itself - IIRC it was actually a no-op.

In this case, however, your code can be improved in simplicity and will
still work in both cases:

static public string DecryptString(string s, byte[] key, byte[] iv ,
SymmetricAlgorithm encryption_algorithm)
{
using(MemoryStream msout = new MemoryStream())
{
byte[] data = Convert.FromBase64String(s);
using(CryptoStream crypto = new CryptoStream(msout,
encryption_algorithm.CreateDecryptor(key,iv),
CryptoStreamMode.Write))
{
crypto .Write(data,0,data.Length);
crypto .FlushFinalBlock();
} // dispose of the cryptostream, we don't need it anymore

data = msout.ToArray();

return System.Text.Encoding.UTF8.GetString(data,0,
data.Length);
}
}

If you're dealing with other streams, you could use my
NonClosingStreamWrapper, available from
http://www.pobox.com/~skeet/csharp/miscutils

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
Harold Howe
11/23/2005 10:59:36 AM

[quoted text, click to view]

<snip>

Thanks. It looks like the main addition in your code is this:

data = msout.ToArray();

So it is safe to use ToArray after the memory stream is closed? The
entire concept of closing a memory stream is somewhat fuzzy to me.

[quoted text, click to view]

Cool. Thanks.

The correct link is http://www.pobox.com/~skeet/csharp/miscutil for
anyone reading the archive of this.


[quoted text, click to view]

..net reflector showed that it wasn't quite a no-op, but it doesn't do a
close or flush either.

H^2
Jon Skeet [C# MVP]
11/23/2005 5:49:04 PM
[quoted text, click to view]

Yes, ToArray is fine after closing the stream. From the docs:

<quote>
Note
This method works when the MemoryStream is closed.
</quote>

[quoted text, click to view]

Whoops - sorry!

[quoted text, click to view]

The point I noticed when I looked before is that it doesn't flush the
final block (which is part of Close, IIRC).

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
AddThis Social Bookmark Button