我正在读取一个加密文件,并且想在密码不正确时抛出一个特定的错误。由于使用不正确的密码解密只会成功但返回乱码数据,我想确定密码是否正确。
我这样做的方法是向加密文件写入一个“魔法值”;假设我将值写入MaGiC
文件。每当我解密文件时,我都会确保前 5 个字节包含MaGiC
. 如果不是,用于解密文件的密码一定是错误的,所以我抛出一个InvalidPasswordException
.
MAGICHEADER = new byte[] { 0x4D, 0x61, 0x47, 0x69, 0x43 }; // "MaGiC"
using (var fs = File.OpenRead(path))
using (var algo = ...)
using (var cs = new CryptoStream(fs, algo.CreateDecryptor(), CryptoStreamMode.Read))
{
var hdr = new byte[MAGICHEADER.Length]; // Buffer
cryptoStream.Read(hdr, 0, hdr.Length); // Read magic header from encrypted stream
// If the decrypted data doesn't equal the magic header this means the password is wrong
if (!MAGICHEADER.SequenceEqual(hdr))
throw new InvalidPasswordException();
// ... read rest of file
}
为简洁起见,我遗漏了很多东西(算法、密钥、IV、块大小、填充、模式等)。对于这种特殊情况,可能重要的是:我正在使用PKCS7
填充(但我很确定所有填充都会导致所描述的问题)。
现在,在调用端,我编写了如下代码:
try {
var data = ReadFile("C:\foo\bar", "INCORRECTPASSWORD");
// ... Do stuff with data
} catch (InvalidPasswordException) {
// Oh noes! Wrong password! Ask to enter password again
}
然而,令我惊讶的InvalidPasswordException
是并没有被抓住;我确实得到了一个异常,但类型为CryptographicException
:填充无效,无法删除。.
当我调试问题时,我看到InvalidPasswordException
被抛出。我也想我知道发生了什么:InvalidPasswordException
抛出,using
导致CryptoStream
被处理,并且CryptoStream
确定由于我们不在流的末尾,剩下的必须是“填充”,然后导致异常。或者至少是类似的东西。
要“强制”抛出我的异常,我可以执行以下操作:
if (!MAGICHEADER.SequenceEqual(hdr)) {
try { cs.FlushFinalBlock(); } catch { } // YUK!!
throw new InvalidPasswordException();
}
或者:
if (!MAGICHEADER.SequenceEqual(hdr)) {
try { cs.Dispose(); } catch { } // YUK!!
throw new InvalidPasswordException();
}
然而,我希望有一个更优雅的解决方案。有没有办法可以初始化CryptoStream
不扔处置?还是一种CryptoStream
干净地“关闭”而不扔的方法?我已经尝试过Close()
,Clear()
等等,但是所有这些方法也导致CryptoGraphicException
我try { ... } catch { ... }
在扔掉自己的InvalidPasswordException
.