Недопустимый пробел и его нельзя удалить?

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

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

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

public void Cryptography(XmlDocument doc, bool cryptographyMode)
{
    RijndaelManaged key = null;
    try
    {
    // Create a new Rijndael key.
    key = new RijndaelManaged();
    const string passwordBytes = "Password1234"; //password here 

    byte[] saltBytes = Encoding.UTF8.GetBytes("SaltBytes");
    Rfc2898DeriveBytes p = new Rfc2898DeriveBytes(passwordBytes, saltBytes);
    // sizes are devided by 8 because [ 1 byte = 8 bits ] 
    key.IV = p.GetBytes(key.BlockSize/8);
    key.Key = p.GetBytes(key.KeySize/8);

    if (cryptographyMode)
    {
        Ecrypt(doc, "Content", key);
    }
    else
    {
        Decrypt(doc, key);
    }

    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
    finally
    {
    // Clear the key.
    if (key != null)
    {
        key.Clear();
    }
    }

}

private void Decrypt(XmlDocument doc, SymmetricAlgorithm alg)
{
    // Check the arguments.  
    if (doc == null)
    throw new ArgumentNullException("Doc");
    if (alg == null)
    throw new ArgumentNullException("alg");

    // Find the EncryptedData element in the XmlDocument.
    XmlElement encryptedElement = doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;

    // If the EncryptedData element was not found, throw an exception.
    if (encryptedElement == null)
    {
    throw new XmlException("The EncryptedData element was not found.");
    }


    // Create an EncryptedData object and populate it.
    EncryptedData edElement = new EncryptedData();
    edElement.LoadXml(encryptedElement);

    // Create a new EncryptedXml object.
    EncryptedXml exml = new EncryptedXml();


    // Decrypt the element using the symmetric key.
    byte[] rgbOutput = exml.DecryptData(edElement, alg); <----  I GET THE EXCEPTION HERE
    // Replace the encryptedData element with the plaintext XML element.
    exml.ReplaceData(encryptedElement, rgbOutput);

}

Ответ 1

Rijndael/AES - это блочный шифр. Он шифрует данные в 128-битных (16-символьных) блоках. Криптографическое заполнение используется, чтобы убедиться, что последний блок сообщения всегда имеет правильный размер.

Ваш метод дешифрования ожидает, какой бы ни была его вставка по умолчанию, и не находит ее. Как говорит @NetSquirrel, вам нужно явно установить заполнение для шифрования и дешифрования. Если у вас нет причин поступать иначе, используйте отступы PKCS # 7.

Ответ 2

Убедитесь, что ключи, которые вы используете для шифрования и дешифрования, одинаковы. Метод заполнения, даже если он явно не задан, должен по-прежнему допускать надлежащее дешифрование/шифрование (если не установлено, они будут одинаковыми). Однако, если вы по какой-то причине используете другой набор ключей для дешифрования, чем используется для шифрования, вы получите эту ошибку:

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

Если вы используете какой-то алгоритм для динамического генерации ключей, которые не будут работать. Они должны быть одинаковыми для шифрования и дешифрования. Один из распространенных способов состоит в том, чтобы вызывающая сторона предоставляла ключи в конструкторе класса методов шифрования, чтобы предотвратить процесс шифрования/дешифрования с любой рукой при создании этих элементов. Он фокусируется на задаче (шифрование и дешифрование данных) и требует, чтобы вызывающий вызывал iv и key.

Ответ 3

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

Это может относиться к ответу rossum, но считалось, что стоит упомянуть.

Ответ 4

Служебные времена битвы, я, наконец, решил проблему.
(Примечание: Я использую стандартный AES как симметричный алгоритм. для всех.)

  • Измените класс алгоритма. Замените класс RijndaelManaged на AESManaged один.
  • Не устанавливайте явный набор KeySize класса алгоритма, оставив их по умолчанию.
    (Это очень важный шаг. Я думаю, что есть ошибка в свойстве KeySize.)

Вот список, который вы хотите проверить, какой аргумент вы могли пропустить:

  • Key
    (массив байтов, длина должна быть ровно одним из 16, 24, 32 байт для разного размера ключа.)
  • IV
    (байтовый массив, 16 байт)
  • CipherMode
    (Один из CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (Один из ANSIX923, ISO10126, None, PKCS7, Zeros)

Ответ 5

Если один и тот же ключ и вектор инициализации используются для кодирования и декодирования, эта проблема связана не с декодированием данных, а с кодированием данных.

После того, как вы вызвали метод Write для объекта CryptoStream, вы должны ВСЕГДА вызывать метод FlushFinalBlock перед методом Close.

Документация MSDN по методу CryptoStream.FlushFinalBlock гласит:
"Вызов метода Close вызовет FlushFinalBlock..."
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs.110).aspx
Это не верно. Вызов метода Close просто закрывает CryptoStream и выходной поток.
Если вы не вызываете FlushFinalBlock до Close после записи данных для шифрования, то при дешифровании данных вызов метода Read или CopyTo для вашего объекта CryptoStream вызовет исключение CryptographicException (сообщение: "Заполнение недопустимо и его нельзя удалить").

Это, вероятно, верно для всех алгоритмов шифрования, полученных из SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), хотя я только что проверил это для AesManaged и MemoryStream в качестве выходного потока.

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

И вам не нужно выполнять какие-либо дополнения программно или выбирать другое значение свойства Padding. Заполнение - это метод метода FlushFinalBlock.

.........

Дополнительное замечание для Кевина:

Да, CryptoStream вызывает FlushFinalBlock перед вызовом Close, но это слишком поздно: когда вызывается метод CryptoStream Close, выходной поток также закрывается.

Если ваш выходной поток является MemoryStream, вы не можете прочитать его данные после его закрытия. Поэтому вам нужно вызвать FlushFinalBlock на вашем CryptoStream, прежде чем использовать зашифрованные данные, записанные в MemoryStream.

Если ваш выходной поток - FileStream, дела обстоят хуже, потому что запись буферизуется. В результате последние записанные байты могут не записываться в файл, если вы закроете поток вывода перед вызовом Flush для FileStream. Поэтому перед вызовом Close для CryptoStream сначала необходимо вызвать FlushFinalBlock для вашего CryptoStream, а затем вызвать Flush для вашего FileStream.

Ответ 6

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

Ответ 7

Другой сценарий, опять же для поиска людей.

Для меня эта ошибка возникла во время метода Dispose(), который замаскировал предыдущую ошибку, не связанную с шифрованием.

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

Ответ 8

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

Решение для меня состояло в том, чтобы разместить

        try
            decryption stuff....
        catch
             inform decryption will not be carried out.
        end try

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

Ответ 9

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

Ответ 10

У меня была такая же ошибка. В моем случае это было потому, что я сохранил зашифрованные данные в базе данных SQL. Таблица, в которой хранятся данные, имеет двоичный (1000) тип данных. При извлечении данных из базы данных он расшифровывает эти 1000 байтов, тогда как там фактически 400 байтов. Таким образом, удаление конечного нуля (600) из результата решило проблему.

Ответ 11

У меня была эта ошибка, и я явно устанавливал размер блока: aesManaged.BlockSize = 128;

Как только я это убрал, все заработало.

Ответ 12

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

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}