我有一些加密代码,像这样(缩写)
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
。我不是在问为什么抛出异常,而是为什么我不能用不同的消息正确地重新抛出它。
答案 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);
}