В расшифровке файла отсутствует ~10 символов от конца

Я написал методы шифрования/дешифрования, используя RC2CryptoServiceProvider на С#, и по какой-то причине я не могу заставить свой дешифратор расшифровать последние несколько байтов. Файл кажется просто обрезанным. Мой метод шифрования выглядит так:

    public static byte[] EncryptString(byte[] input, string password)
    {
        PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null);
        byte[] ivZeros = new byte[8];
        byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros);

        RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider();

        byte[] IV = new byte[8];
        ICryptoTransform encryptor = RC2.CreateEncryptor(pbeKey, IV);

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
        csEncrypt.Write(input, 0, input.Length);
        csEncrypt.FlushFinalBlock();

        return msEncrypt.ToArray();
    }

Пока моя расшифровка выглядит так:

    public static byte[] DecryptString(byte[] input, string password, int originalSize)
    {
        PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null);
        byte[] ivZeros = new byte[8];
        byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros);

        RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider();

        byte[] IV = new byte[8];
        ICryptoTransform decryptor = RC2.CreateDecryptor(pbeKey, IV);

        MemoryStream msDecrypt = new MemoryStream();
        CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);

        csDecrypt.Write(input, 0, originalSize);
       // csDecrypt.FlushFinalBlock();

        char[] decrypted = new char[input.Length];
        decrypted = System.Text.Encoding.UTF8.GetChars(msDecrypt.ToArray());
        return msDecrypt.ToArray();

    }

char[] decrypted возвращает весь расшифрованный файл, за исключением того, что файл заканчивается на </LudoData>, и при расшифровке я добираюсь только до первого символа <.

Я играю с длиной вещей, и ничего ничего не меняется. В моем конкретном случае input имеет длину 11296, а originalSize имеет размер 11290. Однако при расшифровке decrypted оказывается размером 11280. Что дает!


person Mark    schedule 27.10.2009    source источник


Ответы (2)


Есть ли причина, по которой вы закомментировали Flush()? Вы пытались полностью закрыть свои потоки?

person Wayne Hartman    schedule 27.10.2009
comment
Он пишет в оба криптопотока, что означает, что он должен сбросить последний блок в обоих, это точно. - person ; 27.10.2009
comment
Я закомментировал это из-за ошибки времени выполнения, которую я получил, которую я исправил, а затем забыл о Flush. Это как-то все решило. Я вообще ничего не понимаю, но спасибо! - person Mark; 27.10.2009
comment
Итак, да, жалкая проблема флеша снова поднимает голову. Я уже сталкивался с этим много раз. На самом деле, у меня он работал на моем сервере разработки, думая, что все в порядке, а потом БАМ! он поднимает голову в производственной среде - даже с такими же точными данными! Сумасшедший, да? Все из-за того, что забыли смыть. - person Wayne Hartman; 27.10.2009

Вздох, я участвовал в этой битве около месяца назад, и у меня была очень похожая проблема, за исключением того, что я СЛИШКОМ много переживал в конце. ToArray был моим решением.

Ты делаешь здесь какие-то странные вещи, в которых я точно не уверен. Вы используете криптопотоки, когда вам это не нужно, вы отслеживаете исходную длину по какой-то странной причине и используете устаревшие классы. Ваша проблема, вероятно, представляет собой комбинацию заполнения, неверных предположений (о чем свидетельствует originalLength) и неправильной обработки потоков (что может быть сложно). Попробуйте это вместо этого:

Зашифровать:

var rij = RijndaelManaged.Create();
rij.Mode = CipherMode.CBC;
rij.BlockSize = 256;
rij.KeySize = 256;
rij.Padding = PaddingMode.ISO10126;
var pdb = new Rfc2898DeriveBytes(password, 
          Encoding.Default.GetBytes("lolwtfbbqsalt" + password));
var enc = rij.CreateEncryptor(pdb.GetBytes(rij.KeySize / 8), 
          pdb.GetBytes(rij.BlockSize / 8));
return enc.TransformFinalBlock(unencryptedBytes, 0, unencryptedBytes.Length);

Расшифровать:

// throws a cryptographic exception if password is wrong
var rij = RijndaelManaged.Create();
rij.Mode = CipherMode.CBC;
rij.BlockSize = 256;
rij.KeySize = 256;
rij.Padding = PaddingMode.ISO10126;
var pdb = new Rfc2898DeriveBytes(password, 
          Encoding.Default.GetBytes("lolwtfbbqsalt" + password));
var dec = rij.CreateDecryptor(pdb.GetBytes(rij.KeySize / 8), 
          pdb.GetBytes(rij.BlockSize / 8));
return dec.TransformFinalBlock(encryptedBytes, 0, 
          encryptedBytes.Length);

Обратите внимание, что единственным отличием этих двух методов является CreateEncryptor/CreateDecryptor, так что вы можете реорганизовать множество дубликатов. Также обратите внимание, что я получаю массив байтов и получаю массив байтов без использования каких-либо потоков. Это также немного более безопасно, чем RC2, и было бы еще более безопасным, если бы соль была более случайной.

person Community    schedule 27.10.2009
comment
Я использую RC2, потому что он также должен быть совместим с приложением C++, которое принимает зашифрованный файл RC2. - person Mark; 27.10.2009