Nested "using" crashes .net runtime when used with CryptoStream

272 views Asked by At

We have this simple code that was converted from vb.net where it wasn't constructed using using/end using. During conversion we utilized using in c#.

using (var memStream = new MemoryStream() { Position = 0L })
using (ICryptoTransform cryptoTransfrom = (new TripleDESCryptoServiceProvider()).CreateDecryptor(_key, _iv))
{
    using (var cryptStream = new CryptoStream(memStream, cryptoTransfrom, CryptoStreamMode.Write))
    {
        // <-- here used to be try
        string convertedValue = ConvertHexToDec(value);
        byte[] decryptBytes = Convert.FromBase64String(convertedValue); //<-- Error line
        // <-- here used to be catch/throw
        cryptStream.Write(decryptBytes, 0, decryptBytes.Length);
        cryptStream.FlushFinalBlock();
        cryptStream.Close();
    }
    decodedVal = Encoding.ASCII.GetString(memStream.ToArray());
}

But there was try/catch (see comments) surrounding Convert.FromBase64String(convertedValue). What we didn't realize, is that value sometimes came as plain, un-base64-encoded value. So, when un-encoded value hit "Error line" - try/catch did the business of re-throw. But, when you look at the code above, when such value causes exception at that line - .NET Runtime crashes. Here is event log

.NET Runtime version 2.0.50727.5485 - Fatal Execution Engine Error (000007FEE581600A) (80131506)

And exception, of cource, just normal

Invalid character in a Base-64 string.

I fixed it buy removing inner using

using (var memStream = new MemoryStream() { Position = 0L })
using (ICryptoTransform cryptoTransfrom = (new TripleDESCryptoServiceProvider()).CreateDecryptor(_key, _iv))
{
    var cryptStream = new CryptoStream(memStream, cryptoTransfrom, CryptoStreamMode.Write);
    string convertedValue = ConvertHexToDec(value);
    byte[] decryptBytes = Convert.FromBase64String(convertedValue); //<-- Error line      
    cryptStream.Write(decryptBytes, 0, decryptBytes.Length);
    cryptStream.FlushFinalBlock();
    cryptStream.Close();
    decodedVal = Encoding.ASCII.GetString(memStream.ToArray());
}

Now, error, of course still, occurs but it doesn't crash .NET Runtime, therefore acts normal. Also, placing try/catch-rethrow where it was before would prevent such crash as well.

I suspect, it has something to do with nested using. Inner using is not really needed because CryptoStream simply wraps memory stream and transformation. And if error occurs inside curly brackets, it will be propagated to try/catch of transformation first and then memory stream.

But can someone explain such behavior considering that this only happens when assembly runs built for x64 and runs in x64 ASP.NET pool? When application compiled for x86 and runs in 32-bit pool, it doesn't happen.

1

There are 1 answers

1
Eric Lippert On BEST ANSWER

It is undoubtedly a bug in the runtime. Since you are using an extremely old version of the runtime, my advice is to upgrade.

But can someone explain such behavior considering that this only happens when assembly runs built for x64 and runs in x64 ASP.NET pool? When application compiled for x86 and runs in 32-bit pool, it doesn't happen.

The x64 and x86 jitters were completely different codebases in that version. A bug severe enough to crash the runtime involving weird codegen bugs in nested try-finally blocks will almost certainly be unique to a particular jitter.