Как определить, что ключ или вектор неверны, используя Rijndael для расшифровки файла?

Когда я использую неправильный ключ, я получаю «расшифрованный» мусорный файл и исключение из mscorlib.dll: «Указанный размер блока недействителен для этого алгоритма». Вместо этого я хотел бы, чтобы расшифровка полностью завершилась неудачно, не вызывая исключения.

Вот мой текущий код (адаптированный из примера vb.net, который я нашел в Интернете, поэтому было бы лучше, если бы там было лучшее решение)

    public static bool EncryptOrDecryptFile(string strInputFile,
        string strOutputFile, string pKey, string pIv, CryptoAction Direction)
    {
        Byte[] bytKey = CreateKey(pKey);
        Byte[] bytIV = CreateIV(pIv);
        bool pRet = false;
        if (!File.Exists(strInputFile))
            return false;

        try
        {
            using (FileStream fsInput = new FileStream(strInputFile, FileMode.Open, FileAccess.Read))
            {
                using (FileStream fsOutput = new FileStream(strOutputFile, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    fsOutput.SetLength(0);
                    byte[] bytBuffer = new byte[4097];
                    long lngBytesProcessed = 0;
                    long lngFileLength = fsInput.Length;
                    int intBytesInCurrentBlock = 0;
                    CryptoStream csCryptoStream = null;
                    RijndaelManaged cspRijndael = new RijndaelManaged();
                    cspRijndael.BlockSize = 4096;
                    switch (Direction)
                    {
                        case CryptoAction.ActionEncrypt:
                            csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateEncryptor(bytKey, bytIV),
                                                              CryptoStreamMode.Write);
                            break;
                        case CryptoAction.ActionDecrypt:
                            csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateDecryptor(bytKey, bytIV),
                                                              CryptoStreamMode.Write);
                            break;
                    }
                    while (lngBytesProcessed < lngFileLength)
                    {
                        intBytesInCurrentBlock = fsInput.Read(bytBuffer, 0, 4096);
                        csCryptoStream.Write(bytBuffer, 0, intBytesInCurrentBlock);
                        lngBytesProcessed = lngBytesProcessed + Convert.ToInt64(intBytesInCurrentBlock);
                    }
                    csCryptoStream.Close();
                }
            }
            pRet = true;
        }
        catch (Exception ex)
        {
            pRet = false;
        }
        return pRet;
    }
    #endregion
}

person cabgef    schedule 01.03.2011    source источник


Ответы (2)


Учитывая, что любая комбинация битов правильной длины может быть действительным ключом, и то же самое верно для IV, у криптопотока нет возможности определить, является ли он неправильным, пока он не попытается расшифровать последний блок зашифрованного текста. в этот момент он обнаруживает, что заполнение неверно, и выдает исключение. Кроме того, вы не можете использовать любой размер блока, который вы хотите — есть определенные размеры блоков, которые действительны для определенных поставщиков криптографии — для Rijndael, я думаю, допустимые размеры блоков — 128, 192 и 256.

Единственный способ избежать "мусорного" файла - выполнить всю расшифровку в памяти или записать во временный файл, а не в окончательный выходной файл. Невозможно избежать исключения, но в любом случае это должно быть необычным явлением.


Я также избавился бы от всего управления буферами в вашем коде, проверок длины и т. д. и просто использовал бы Stream.CopyTo между входным потоком и потоком шифрования. Например.:

using (FileStream fsInput = new FileStream(strInputFile, FileMode.Open, FileAccess.Read))
{
    using (FileStream fsOutput = new FileStream(strOutputFile, FileMode.OpenOrCreate, FileAccess.Write))
    {
        CryptoStream csCryptoStream = null;
        RijndaelManaged cspRijndael = new RijndaelManaged();
        cspRijndael.BlockSize = 256;
        switch (Direction)
        {
            case CryptoAction.ActionEncrypt:
                csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateEncryptor(bytKey, bytIV),
                                                  CryptoStreamMode.Write);
                break;
            case CryptoAction.ActionDecrypt:
                csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateDecryptor(bytKey, bytIV),
                                                  CryptoStreamMode.Write);
                break;
        }
        fsInput.CopyTo(csCryptoStream);
        csCryptoStream.Close();
    }
}
pRet = true;
person Damien_The_Unbeliever    schedule 01.03.2011
comment
Спасибо. Как сделать FileStream CopyTo в dotnet 3.5? - person cabgef; 01.03.2011
comment
@mikeh - я бы создал метод расширения в Stream и скопировал в него ответ на этот вопрос: stackoverflow.com/questions/1933742/ - person Damien_The_Unbeliever; 01.03.2011
comment
Исключение заполнения не гарантируется для неправильного IV/Key. - person President James K. Polk; 02.03.2011

Ни один из режимов работы не доступен для RijndaelManaged обеспечивать защиту целостности или аутентификацию. Проверка правильности заполнения не является заменой, так как вы можете легко получить неверное сообщение с допустимым заполнением.

Вместо этого следует применить HMAC зашифрованное сообщение.

person aaz    schedule 01.03.2011