C #: ошибка AES: заполнение недопустимо и не может быть удалено.Тот же ключ и все, помогите - PullRequest
6 голосов
/ 22 февраля 2011

Я довольно новичок в C #, поэтому, пожалуйста, будьте терпеливы со мной. Я знаю, что этот вопрос задавали много раз, но я не мог найти ответ на свою проблему.

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

Заполнение недействительно и не может быть удалено.

Я использую тот же ключ и iv (жестко запрограммированный, пока я не получу его работу)

Вот мой код шифрования, который работает без проблем:

        //result
        byte[] data = new byte[32];

        //setup encryption (AES)
        SymmetricAlgorithm aes = Aes.Create();
        byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9,50};
        byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);

        FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);

        //prepare data to write (byte array 'data') ...

        //encrypt
               MemoryStream m = new MemoryStream();
               using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
                   c.Write(data, 0, data.Length);
               data = m.ToArray();
               fStream.Write(data, 0, data.Length);

А вот мой код расшифровки:

FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);

            //setup encryption (AES)
            SymmetricAlgorithm aes = Aes.Create();
            byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
            byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);

            //result
            byte[] data = new byte[32];

            //loop for reading the whole file ...
            int len = fStream.Read(data, 0, 32);

            //decrypt
                MemoryStream m = new MemoryStream();
                using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
                    c.Write(data, 0, data.Length); //The exception is thrown in this line                  
                data = m.ToArray();

                //using the decrypted data and then looping back to reading and decrypting...

Я перепробовал все, что мог придумать (что не так много, потому что я новичок в криптографии), я искал везде и не мог найти решение своей проблемы. Я также помог себе с книгой C # в двух словах .

Если у кого-то есть идеи о том, почему это может произойти, я буду очень благодарен, потому что у меня нет идей.

Спасибо за ваше время и ответы.

EDIT: Кажется, что размер зашифрованных данных составляет 48 байт (на 12 байт больше, чем оригинал). Почему это так? Я думал, что он добавляет байты, только если они не кратны размеру блока (16 байтов, мои данные 32 байта). Всегда ли данные больше и постоянно увеличиваются (мне нужно знать это, чтобы правильно читать и расшифровывать).

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

Ответы [ 3 ]

6 голосов
/ 22 февраля 2011

На основании ваших правок:

РЕДАКТИРОВАТЬ: Кажется, что размер зашифрованных данных составляет 48 байт (на 12 байт больше, чем оригинал).Почему это так?Я думал, что он добавляет байты, только если они не кратны размеру блока (16 байтов, мои данные 32 байта).Всегда ли данные больше и постоянно увеличиваются (мне нужно знать, что для правильного чтения и расшифровки).

Если зашифрованные данные имеют размер 48 байтов, это на 16 байтов больше, чем у исходного массива.Это имеет смысл, поскольку алгоритм с дополнением данных, потому что по умолчанию это PKCS7 (даже если размер соответствует размеру блока, потому что он дополняет следующий кратный размеру блока),Если вы хотите сохранить его ровно 32 байта, просто измените Padding на None

aes.Padding = PaddingMode.None;
3 голосов
/ 22 февраля 2011

Вы, похоже, рассматриваете длину открытого текста как длину зашифрованного текста.Это небезопасное предположение.

Почему вы копируете между FileStream и MemoryStream, вы можете передать FileStream непосредственно в шифратор / расшифровщик.

В PKCS7 имеется минимум один байт заполнения (для хранения количества байтов заполнения).Таким образом, выходной размер будет Ceil16(input.Length + 1) или (input.Length & ~15) + 1.

2 голосов
/ 22 февраля 2011

Короче говоря, AES шифрует сообщения блоками по 16 байт. Если ваше сообщение не кратно 16 байтам, алгоритм должен немного отличаться для последнего блока; в частности, последний блок должен быть «дополнен» значением, известным алгоритму как значение заполнения (обычно ноль, иногда что-то еще, например символ пробела).

Вы делаете это самостоятельно, помещая данные в байтовый массив фиксированной длины. Вы дополнили данные самостоятельно, но теперь расшифровщик пытается распаковать последний блок и получить байтовые значения, которые он не распознает как заполнение, которое добавил бы его аналог шифратора.

Ключ не дополняет сообщение. Вы можете использовать класс BitConverter для приведения байтовых массивов к типам IConvertible (типам значений и строкам) и затем использовать их вместо преобразования своего собственного байтового массива. Затем, когда вы расшифровываете, вы можете читать из потока дешифрования вплоть до длины зашифрованного текста, но не ожидайте, что в дешифрованном результате будет столько фактических байтов.

...