1

我正在读取一个加密文件,并且想在密码不正确时抛出一个特定的错误。由于使用不正确的密码解密只会成功但返回乱码数据,我想确定密码是否正确。

我这样做的方法是向加密文件写入一个“魔法值”;假设我将值写入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()等等,但是所有这些方法也导致CryptoGraphicExceptiontry { ... } catch { ... }在扔掉自己的InvalidPasswordException.

4

0 回答 0