使用加密后,在终结器线程中获取“ReleaseHandleFailed”MDA

时间:2011-05-08 13:16:34

标签: c# cryptography

我在循环中使用第二次运行此代码后获得了MDA(使用不同的file参数:

byte[] encryptedData = File.ReadAllBytes(file); // before this line it throws, see exception below
long dataOffset;

using (var stream = new MemoryStream(encryptedData))
using (var reader = new BinaryReader(stream))
{
    // ... read header information which is not encrypted
}


using (var stream = new MemoryStream(encryptedData))
{
    stream.Seek(dataOffset, SeekOrigin.Begin);

    using (var aesAlg = new AesCryptoServiceProvider())
    using (var decryptor = aesAlg.CreateDecryptor(key, iv))
    using (var csDecrypt = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
    using (var reader = new BinaryReader(csDecrypt))
    {
        decrypted = reader.ReadBytes((int)(encryptedData.Length - dataOffset));
    }
}

MDA如下:

  

“Microsoft.Win32.SafeHandles.SafeCapiKeyHandle”类型的SafeHandle或CriticalHandle无法正确释放值为0x000000001BEA9B50的句柄。这通常表示通过其他方式错误地释放了句柄(例如使用DangerousGetHandle提取句柄并直接关闭它或在其周围构建另一个SafeHandle。)

堆栈跟踪没有太多信息:

  

mscorlib.dll!System.Runtime.InteropServices.SafeHandle.Dispose(bool disposing)+ 0x10 bytes       mscorlib.dll!System.Runtime.InteropServices.SafeHandle.Finalize()+ 0x1a bytes

我怀疑其中一个流或CryptoServiceProvider由于某种原因未发布。除此之外,代码运行良好,并做到了预期。 MDA在控件到达方法的第一行之前发生。

我该怎么做呢?问题的根本原因是什么?

1 个答案:

答案 0 :(得分:7)

显然终结器线程正在最终确定已经处理好的SafeHandle。这是AesCryptoServiceProvider.Dispose(bool)方法的实现:

protected override void Dispose(bool disposing)
{
    try {
        if (disposing) {
            if (this.m_key != null) this.m_key.Dispose();
            if (this.m_cspHandle != null) this.m_cspHandle.Dispose();
        }
    }
    finally {
        base.Dispose(disposing);
    }
}

三个错误:

  • 处理它后,它不会将m_key字段设置为null
  • GC.SuppressFinalize()未被调用,甚至不被.NET 3.5中的基类调用
  • SafeCapiKeyHandle类不会使其ReleaseHandle()方法中存储的句柄失效。

所有三个错误的组合足以触发此MDA。它仍然在.NET 4.0中被窃听,但至少GC.SuppressFinalize由SymmetricAlgorithm.Dispose(bool)调用,因此不会使用终结器。

鼓励看到框架大师搞砸了。您可以在connect.microsoft.com上报告问题。要阻止调试器唠叨这一点,请使用Debug + Exceptions,Managed Debugging Assistants,取消ReleaseHandleFailed。默认情况下,这个是未被攻击的,这肯定是你第一个注意到这个错误的原因。

我认为第三个错误使这成为一个关键问题btw,从技术上讲,这个bug可能会导致回收句柄值被关闭。虽然赔率非常小。相当具有讽刺意味,因为这是一个安全的手柄类。