Rijndael отступ или длина недействительн - PullRequest
1 голос
/ 06 марта 2012

Я пытаюсь зашифровать / дешифровать строку, используя Eith Rijndael или Aes и приведенный ниже код.

public class Crypto
{
    private const string defaultVector = "asdfg123456789";
    private const CipherMode cipherMode = CipherMode.CBC;
    //Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7
    private const PaddingMode paddingMode = PaddingMode.ISO10126;
    private const int iterations = 2;
    private static Rijndael GetCrypto(string passphrase)
    {
        var crypt = Rijndael.Create();
        crypt.Mode = cipherMode;
        crypt.Padding = paddingMode;
        crypt.BlockSize = 256;
        crypt.KeySize = 256;
        crypt.Key =
            new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
        return crypt;
    }
    public static string Encrypt(string plainText, string passphrase)
    {
        byte[] clearData = Encoding.Unicode.GetBytes(plainText);
        byte[] encryptedData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearData, 0, clearData.Length);
                //cs.FlushFinalBlock(); //Have tried this active and commented with no change.
            }
            encryptedData = ms.ToArray();
        }
        //Changed per Xint0's answer.
        return Convert.ToBase64String(encryptedData);
    }
    public static string Decrypt(string cipherText, string passphrase)
    {
        //Changed per Xint0's answer.
        byte[] encryptedData = Convert.FromBase64String(cipherText);
        byte[] clearData;
        var crypt = GetCrypto(passphrase);
        using (var ms = new MemoryStream())
        {
                using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(encryptedData, 0, encryptedData.Length);
                    //I have tried adding a cs.FlushFinalBlock(); here as well.
                }
                clearData = ms.ToArray();
        }
        return Encoding.Unicode.GetString(clearData);
    }
}

// Редактирует: я изменил вызовы Unicode для Convert.ToBase64String согласно ответу Xint0 ниже,

На методе cs.Write in Decrypt я получаю сообщение об ошибке «Заполнение недопустимо и не может быть удалено».

Я попытался установить для PaddingMode значение. Нет, но получаю«Длина данных для шифрования недействительна».на cs.Write в методе Encrypt.

Я смотрел на них, и, похоже, ничего из того, что они сказали, не работает.

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

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

Трассировка стека показывает System.Security.CryptographicException от RijndaelManagedTransform.DecryptData (Byte [] inputBuffer, Int32 inputOffset, Int32Int32 inputCount, Byte [] & outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast).

Ответы [ 3 ]

3 голосов
/ 13 июля 2012

Я потратил много времени на то, чтобы найти причину CryptographicException , и я тоже гуглил, включая Stackoverflow.
Это была глупая ошибка (как часто бывает при программировании с использованием copy-paste), так какследуйте:

Он вызывал метод FlushFinalBlock () из экземпляра CryptoStream .

Посмотрите на НЕПРАВИЛЬНЫЙ код:

CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);

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

Будьте осторожны и проверьте это, чтобы не тратить свое драгоценное время;)

С уважением
Бронек

1 голос
/ 06 марта 2012

Я вижу две проблемы:

  1. Вы не очищаете и не закрываете потоки перед вызовом ms.ToArray(). Измените его на:

    ...
    using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
    {
        cs.Write(clearData, 0, clearData.Length);
        cs.FlushFinalBlock();
        cs.Close();
    }
    
    ms.Close();
    encryptedData = ms.ToArray();
    ...
    
  2. В Encrypt результирующий байтовый массив encryptedData является NOT строкой Unicode, но вы используете кодировщик Unicode для получения строки из байтового массива. Вместо этого используйте System.Convert.ToBase64String() в Encrypt и System.Convert.FromBase64String() в Decrypt.

В Encrypt до:

return System.Convert.ToBase64String(encryptedData);

В Decrypt до:

byte[] encryptedData = System.Convert.FromBase64String(cipherText);

EDIT

Самая большая проблема - возвращаемое значение Encrypt. Результатом шифрования байтового представления строки Unicode является NOT байтовое представление строки Unicode. Не следует использовать значение encryptedData с Encoding.Unicode.GetString(), чтобы получить строковое представление зашифрованных данных. Используйте System.Convert.ToBase64String(), чтобы получить строковое представление зашифрованных данных. См. Раздел «Замечания» в документации Класс кодирования MSDN.

РЕДАКТИРОВАТЬ 2

Обратите внимание, что Rijndael не совсем AES, если вы взаимодействуете с AES, размер блока всегда должен быть 128 бит, независимо от размера ключа. Подробнее об этом можно прочитать здесь .

0 голосов
/ 02 февраля 2015

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

MemoryStream ms = new MemoryStream(cipherText);
...