Как бросить при использовании CryptoStream, не вызывая CryptoGraphicException
Я читаю зашифрованный файл и хочу выдать конкретную ошибку всякий раз, когда пароль неверный. Поскольку дешифрование с использованием неверного пароля будет просто успешным, но вернет бессмысленные данные, я хотел бы определить, является ли пароль правильным.
То, как я это делаю, я записываю "магическое значение" в зашифрованный файл; скажем, я пишу значение 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
,