重新抛出 CryptographicException 保留原始异常
Rethrowing CryptographicException retains original exception
我有一些密码学代码,像这样(缩写)
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
但是 Messagebox 输出了我所期望的:From Test
所以cryptstream.CopyTo(msVerifyOut)
的异常抛出方式肯定和验证版本有一些区别,但我想不出有什么区别。
作为参考,抛出的异常是:Padding is invalid and cannot be removed
。我不是问为什么抛出异常,而是问为什么我不能用不同的消息正确地重新抛出它。
这是一个有趣的问题。让我们看看到底发生了什么。
我有一些代码(是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)
。
我们来看调试window:
"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);
}
我有一些密码学代码,像这样(缩写)
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
但是 Messagebox 输出了我所期望的:From Test
所以cryptstream.CopyTo(msVerifyOut)
的异常抛出方式肯定和验证版本有一些区别,但我想不出有什么区别。
作为参考,抛出的异常是:Padding is invalid and cannot be removed
。我不是问为什么抛出异常,而是问为什么我不能用不同的消息正确地重新抛出它。
这是一个有趣的问题。让我们看看到底发生了什么。
我有一些代码(是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)
。
我们来看调试window:
"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);
}