El relleno no es válido y no se puede quitar?


He buscado en línea lo que significa esta excepción en relación con mi programa, pero parece que no puedo encontrar una solución o la razón por la que está sucediendo a mi programa específico. He estado usando el ejemplo proporcionado por mi msdn para cifrar y descifrar un XmlDocument usando el algoritmo Rijndael. El cifrado funciona bien, pero cuando intento descifrar, obtengo la siguiente excepción:

El relleno no es válido y no se puede eliminar

¿Puede alguien decirme lo que puedo hacer para resolver este problema? Mi código a continuación es donde obtengo la clave y otros datos. Si el cryptoMode es false, llamará al método decrypt, que es donde se produce la excepción:

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

}
Author: demongolem, 2011-12-21

11 answers

Rijndael/AES es un cifrado de bloques. Encripta los datos en bloques de 128 bits (16 caracteres). El relleno criptográfico se usa para asegurarse de que el último bloque del mensaje tenga siempre el tamaño correcto.

Su método de descifrado está esperando lo que su relleno predeterminado es, y no lo está encontrando. Como dice @NetSquirrel, debe establecer explícitamente el relleno tanto para el cifrado como para el descifrado. A menos que tenga una razón para hacer lo contrario, use el relleno PKCS # 7.

 56
Author: rossum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-21 12:56:54

Asegúrese de que las teclas que se utilizan para cifrar y descifrar son el mismo. El método de relleno, incluso si no se establece explícitamente, debería permitir el descifrado/cifrado adecuado (si no se establece, serán los mismos). Sin embargo, si por alguna razón está utilizando un conjunto diferente de claves para el descifrado que se utiliza para el cifrado que obtener este error:

El relleno no es válido y no se puede eliminar

Si está utilizando algún algoritmo para genere dinámicamente claves que no funcionarán. Deben ser iguales tanto para el cifrado como para el descifrado. Una forma común es hacer que la persona que llama proporcione las claves en el constructor de la clase métodos de cifrado, para evitar que el proceso de cifrado/descifrado tenga alguna mano en la creación de estos elementos. Se centra en la tarea en cuestión (cifrar y descifrar datos) y requiere que el llamante proporcione iv y key.

 33
Author: atconway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-31 16:08:11

Para el beneficio de las personas que buscan, puede valer la pena verificar la entrada que se está descifrando. En mi caso, la información que se envía para descifrar estaba (erróneamente) entrando como una cadena vacía. Resultó en el error de relleno.

Esto puede estar relacionado con la respuesta de rossum, pero creo que vale la pena mencionarlo.

 21
Author: HockeyJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-28 15:08:29

A serval times of fighting, finalmente resolví el problema.
(Nota: Uso AES estándar como algoritmo simétrico. Esta respuesta puede no ser adecuada para todos.)

  1. Cambie la clase del algoritmo. Sustitúyase la clase RijndaelManaged por AESManaged una.
  2. No establezca explícitamente la clase KeySize de algorithm, dejándolos por defecto.
    (Este es el paso muy importante. Creo que hay un error en la propiedad KeySize.)

Aquí hay una lista que desea verificar qué argumento podría han fallado:

  • Clave
    (matriz de bytes, la longitud debe ser exactamente uno de 16, 24, 32 bytes para diferentes tamaños de clave.)
  • IV
    (matriz de bytes, 16 bytes)
  • Cifromodo
    (Uno de CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (Uno de ANSIX923, ISO10126, Ninguno, PKCS7, Ceros)
 7
Author: Johnny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-21 08:20:47

Si se utiliza la misma clave y el mismo vector de inicialización para codificar y decodificar, este problema no proviene de la decodificación de datos, sino de la codificación de datos.

Después de llamar al método Write en un objeto CryptoStream, siempre debe llamar al método FlushFinalBlock antes del método Close.

Documentación de MSDN en CryptoStream.El método FlushFinalBlock dice:
" Llamar al método Close llamará a FlushFinalBlock ..."
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs. 110).aspx
Esto está mal. Llamar al método Close solo cierra el CryptoStream y el flujo de salida.
Si no llama a FlushFinalBlock antes de Cerrar después de escribir los datos para cifrarlos, al descifrar los datos, una llamada al método Read o CopyTo en su objeto CryptoStream generará una excepción CryptographicException (mensaje: "El relleno no es válido y no puede ser quitar").

Esto es probablemente cierto para todos los algoritmos de cifrado derivados de SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), aunque acabo de verificar que para AesManaged y un MemoryStream como flujo de salida.

Por lo tanto, si recibe esta excepción CryptographicException en el descifrado, lea el valor de la propiedad Longitud del flujo de salida después de escribir sus datos para ser cifrados, luego llame a FlushFinalBlock y lea su valor nuevamente. Si ha cambiado, sabes que llamar FlushFinalBlock NO es opcional.

Y no es necesario realizar ningún relleno mediante programación, o elegir otro valor de propiedad de relleno. El relleno es un trabajo de método FlushFinalBlock.

.........

Observación adicional para Kevin:

Sí, CryptoStream llama a FlushFinalBlock antes de llamar a Close, pero es demasiado tarde: cuando se llama al método CryptoStream Close, el flujo de salida también se cierra.

Si su flujo de salida es un MemoryStream, no puede leer su datos después de que se cierra. Por lo tanto, debe llamar a FlushFinalBlock en su CryptoStream antes de usar los datos cifrados escritos en el MemoryStream.

Si su flujo de salida es un FileStream, las cosas son peores porque la escritura está en búfer. La consecuencia es que los últimos bytes escritos pueden no escribirse en el archivo si cierra el flujo de salida antes de llamar a Flush en FileStream. Entonces, antes de llamar a Close en CryptoStream, primero debe llamar a FlushFinalBlock en su CryptoStream y luego llamar a Flush on tu FileStream.

 5
Author: figolu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-18 09:06:15

Mi problema fue que la contraseña del cifrado no coincidía con la contraseña del descifrado... así que lanzó este error .. un poco engañoso.

 2
Author: ecklerpa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-25 16:43:23

Otro escenario, de nuevo para el beneficio de las personas que buscan.

Para mí, este error ocurrió durante el método Dispose() que enmascaró un error anterior no relacionado con el cifrado.

Una vez que se arregló el otro componente, esta excepción desapareció.

 0
Author: Clay Lenhart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-14 14:31:15

Encontré este error de relleno cuando editaba manualmente las cadenas cifradas en el archivo (usando el bloc de notas) porque quería probar cómo se comportaría la función de descifrado si mi contenido cifrado se alteraba manualmente.

La solución para mí fue colocar un

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

Como dije, mi error de relleno fue porque estaba escribiendo manualmente sobre el texto descifrado usando el bloc de notas. Puede que mi respuesta te guíe a tu solución.

 0
Author: webzy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-13 19:25:38

La solución que solucionó la mía fue que inadvertidamente había aplicado diferentes claves a los métodos de Cifrado y Descifrado.

 0
Author: Rondakay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-09 15:01:33

Tuve el mismo error. En mi caso fue porque he almacenado los datos cifrados en una base de datos SQL. La tabla en la que se almacenan los datos tiene un tipo de datos binario(1000). Al recuperar los datos de la base de datos, descifraría estos 1000 bytes, mientras que en realidad había 400 bytes. Así que eliminando el cero final (600) del resultado solucionó el problema.

 0
Author: Martijn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 09:00:43

Me encontré con este error al intentar pasar una ruta de archivo no cifrada al método de descifrado.La solución era comprobar si el archivo pasado está cifrado primero antes de intentar descifrar

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}
 -3
Author: usefulBee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-09 17:15:11