【问题标题】:Rethrowing CryptographicException retains original exception重新抛出 CryptographicException 保留原始异常
【发布时间】:2018-03-18 13:04:43
【问题描述】:

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

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 的原始异常,在这里无关紧要)并带有自定义消息。

我希望消息框显示: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

但这里的消息框输出了我所期望的:From Test

所以cryptstream.CopyTo(msVerifyOut)抛出异常的方式肯定和验证版有一些不同,但是我不知道有什么区别。

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

【问题讨论】:

  • 还有其他代码用来显示消息框吗?也许那是使用 GetBaseException()。
  • @N0Alias 不,这是我自己的一个小程序,仅此而已。当我打破cryptstream.CopyTo(msVerifyOut) 并单步执行时,它只是跳入Catch,抛出新异常,完成流的Using 块,然后进入包含消息框的外部Catch 块。稍后我会考虑将其放在 Github 上以获取完整代码(现在不能)。

标签: vb.net exception-handling


【解决方案1】:

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

我有一些代码(是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 再次被抛出。因此,我们看到了一个不正确的异常。

问题在于退出using 块后调用的CryptoStream.Dispose() 方法。它可能调用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);
}

【讨论】:

  • 简洁,很好地解释了这一点,并且确实是初学者的陷阱。欢迎来到 StackOverflow。
猜你喜欢
  • 2015-10-26
  • 2019-02-22
  • 1970-01-01
  • 2011-01-22
  • 2011-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
相关资源
最近更新 更多