Using “Using” in F#

I was translating a piece of supposedly idiomatic C# AES crypto code to F# and couldn’t understand why the encrypt-decrypt roundtrip did not produce identical values. In fact I got an exception in the decryption function.

The interesting C# fragment:

using (var msEncrypt = new MemoryStream())
{
	msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
	msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
	using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
	{
		using (var swEncrypt = new StreamWriter(csEncrypt))
		{
			swEncrypt.Write(plainText);
		}
	}
	outStr = Convert.ToBase64String(msEncrypt.ToArray());
}

The first F# translation:

use msEncrypt = new MemoryStream()
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof<int>)
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length)
use csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
use swEncrypt = new StreamWriter(csEncrypt)
swEncrypt.Write(plainText)
outStr <- Convert.ToBase64String(msEncrypt.ToArray())

The problem here is that when we take out the bytes from the MemoryStream the encryption streams have not been disposed and therefore not flushed. There is also a special CryptoStream method FlushFinalBlock that needs to be called.

The next F# translation fixes this issue:

use msEncrypt = new MemoryStream()
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof<int>)
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length)
use csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
use swEncrypt = new StreamWriter(csEncrypt)
swEncrypt.Write(plainText)
swEncrypt.Flush()
csEncrypt.FlushFinalBlock()
swEncrypt.Flush()
outStr <- Convert.ToBase64String(msEncrypt.ToArray())

This doesn’t look all that nice though but when using “use” we have to do this in order to make sure the data is flushed because the compiler puts the disposal code at the end of the function – *after* the msEncrypt.ToArray() expression.

The final F# translation uses the F# analogue to the C# using statement, with the same semantics, so our mechanic (read: thoughtless) translation works:

use msEncrypt = new MemoryStream()
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof<int>)
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length)
using (new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) (fun csEncrypt ->
	using (new StreamWriter(csEncrypt)) (fun swEncrypt ->
		swEncrypt.Write(plainText)
	)
)
outStr <- Convert.ToBase64String(msEncrypt.ToArray())

I didn’t bother using “using” for msEncrypt as well, but you get the point, and this did the trick.

In general using “use” flattens the F# code so it has less of an arrow shape without indentation but sometimes it can be useful to have more control over disposing semantics – as in this gotcha.

Advertisements

About xosfaere

Software Developer
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s