Как определить, что ключ или вектор неверны, используя Rijndael для расшифровки файла? - PullRequest
1 голос
/ 01 марта 2011

Когда я использую неправильный ключ, я получаю «расшифрованный» файл мусора и исключение из 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
}

Ответы [ 2 ]

1 голос
/ 01 марта 2011

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

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

1 голос
/ 01 марта 2011

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

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


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

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;
...