Rethrowing CryptographicException保留原始异常

时间:2018-03-18 13:04:43

标签: vb.net exception-handling

我有一些加密代码,像这样(缩写)

Public Class Encryption
    Public Sub DoEncryption()
        [...]
        Try
            cryptstream.CopyTo(msVerifyOut)
        Catch ex As System.Security.Cryptography.CryptographicException
            Throw New System.Security.Cryptography.CryptographicException("Not a valid keyfile or password incorrect", ex)
        End Try
        [...]
    End Sub
End Class

Public Class MainClass
    Public Sub UseEncryption
        [...]
        Dim Encrypter As New Encryption
        Try
            Encrypter.DoEncryption()
        Catch ex As System.Security.Cryptography.CryptographicException
            MessageBox.Show("Encryption failed: " & vbCrLf & ex.Message)
        End Try
        [...]
    End Sub
End Class

因此,cryptstream.CopyTo(msVerifyOut)行可能会抓住被捕获的CryptographicException并重新投放新CryptographicException(有或没有InnerException的原始例外,不会在这里,请使用自定义消息。

我希望Messagebox说:Encryption failed: Not a valid keyfile or password incorrect。但它并没有。它代之以Encryption failed: Original exception message

我尝试重新创建它:

Private Function Test() As Object
    Try
        Dim tst1 = Test1()
        Return tst1
    Catch ex As CryptographicException
        Throw New CryptographicException("From Test", ex)
    End Try
End Function
Private Function Test1() As Object
    Throw New CryptographicException("From Test1")
End Function
Private Sub PerformTest()
    Try
        Dim tst = Test()
    Catch ex As CryptographicException
        MessageBox.Show(ex.Message)
    End Try
End Sub

但是Messagebox会输出我期望的内容:From Test

因此cryptstream.CopyTo(msVerifyOut)引发异常的方式必须与验证版本有所不同,但我无法弄清楚区别是什么。

作为参考,抛出的异常是:Padding is invalid and cannot be removed。我不是在问为什么抛出异常,而是为什么我不能用不同的消息正确地重新抛出它。

1 个答案:

答案 0 :(得分:3)

这是一个有趣的问题。让我们看看实际发生了什么。

我有一些代码(它是C#,但我相信你会理解我的意思):

using (var mem = new MemoryStream(data))
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
using (var cryptoStream = new CryptoStream(mem, decryptor, CryptoStreamMode.Read))
using (var bin = new BinaryReader(cryptoStream))
{
    try
    {
        return bin.ReadBytes(data.Length);
    }
    catch (CryptographicException ex)
    {
        throw new Exception("Invalid password", ex);
    }
}

当我输入错误的密码时,我会看到CryptographicException而不是我自己的new Exception("Invalid password", ex)

让我们看看调试窗口:

"System.Security.Cryptography.CryptographicException" in System.Private.CoreLib.dll
"System.Exception" in my.dll
"System.Security.Cryptography.CryptographicException" in System.Security.Cryptography.Algorithms.dll

正如您所看到的,我的异常被正确抛出,但在它之后,新的CryptographicException再次被抛出。因此,我们看到了不正确的异常。

问题出在CryptoStream.Dispose()方法中,从using块退出后调用。它可能调用FlushFinalBlock()方法,抛出第二个CryptographicException。更多信息https://github.com/dotnet/corefx/issues/7779

所以,将try / catch移到外面,你会得到你想要的东西:

try
{
    using (var mem = new MemoryStream(data))
    using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
    using (var cryptoStream = new CryptoStream(mem, decryptor, CryptoStreamMode.Read))
    using (var bin = new BinaryReader(cryptoStream))
    {
        return bin.ReadBytes(data.Length);
    }
}
catch (CryptographicException ex)
{
    throw new Exception("Invalid password", ex);
}