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 le ocurre a mi programa específico. He estado usando el ejemplo provisto por mi msdn para encriptar y desencriptar un XmlDocument usando el algoritmo de Rijndael. El cifrado funciona bien, pero cuando intento descifrar, obtengo la siguiente excepción:
El relleno no es válido y no se puede quitar
¿Alguien puede decirme qué puedo hacer para resolver este problema? Mi código a continuación es donde obtengo la clave y otros datos. Si el cryptoMode es falso, llamará al método de descifrado, que es donde ocurre 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);
}
c#
cryptography
Amor marrón
fuente
fuente
Respuestas:
Rijndael / AES es un cifrado en bloque. Cifra datos en bloques de 128 bits (16 caracteres). El relleno criptográfico se utiliza para asegurarse de que el último bloque del mensaje tenga siempre el tamaño correcto.
Su método de descifrado espera cualquiera que sea su relleno predeterminado y no lo encuentra. Como dice @NetSquirrel, debe configurar 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.
fuente
alg.Padding = PaddingMode.PKCS7;
Asegúrese de que las claves que utiliza para cifrar y descifrar sean las mismas . El método de relleno, incluso si no se establece explícitamente, debería permitir un descifrado / cifrado adecuado (si no se establece, será el mismo). Sin embargo, si por alguna razón está utilizando un conjunto de claves diferente para el descifrado que el utilizado para el cifrado , obtendrá este error:
Si está utilizando algún algoritmo para generar claves dinámicamente, no funcionará. 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 de métodos de cifrado, para evitar que el proceso de cifrado / descifrado intervenga en la creación de estos elementos. Se centra en la tarea en cuestión (el cifrado y descifrado de datos) y requiere que el
iv
ykey
para ser suministrado por el llamante.fuente
Para el beneficio de las personas que realizan búsquedas, puede valer la pena comprobar la entrada que se está descifrando. En mi caso, la información que se envía para descifrar entraba (incorrectamente) como una cadena vacía. Resultó en el error de relleno.
Esto puede estar relacionado con la respuesta de Rossum, pero pensó que valía la pena mencionarlo.
fuente
Si se utilizan 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.
La documentación de MSDN sobre el método CryptoStream.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 es incorrecto. Llamar al método Close simplemente cierra CryptoStream y el flujo de salida.
Si no llama a FlushFinalBlock antes de Close 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 se puede eliminar").
Esto probablemente sea cierto para todos los algoritmos de cifrado derivados de SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), aunque acabo de verificarlo 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 Stream Length de salida después de escribir sus datos para encriptarlos, luego llame a FlushFinalBlock y lea su valor nuevamente. Si ha cambiado, sabrá que llamar a FlushFinalBlock NO es opcional.
Y no es necesario realizar ningún relleno mediante programación ni elegir otro valor de propiedad de relleno. El relleno es un trabajo del método FlushFinalBlock.
.........
Comentario 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 sus datos después de cerrarlo. Por lo tanto, debe llamar a FlushFinalBlock en su CryptoStream antes de usar los datos cifrados escritos en MemoryStream.
Si su flujo de salida es un FileStream, las cosas empeoran porque la escritura está almacenada 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 en su FileStream.
fuente
Stream.Close()
llamadasthis.Dispose(true)
. El códigoCryptoStream.Dispose(bool)
es:if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
Un tiempo de serval de lucha, finalmente resolví el problema.
(Nota: uso AES estándar como algoritmo simétrico. Esta respuesta puede no ser adecuada para todos).
RijndaelManaged
clase porAESManaged
una.KeySize
clase de algoritmo, déjelas predeterminadas.(Este es el paso muy importante. Creo que hay un error en la propiedad KeySize).
Aquí hay una lista en la que desea verificar qué argumento puede haber pasado por alto:
(matriz de bytes, la longitud debe ser exactamente uno de 16, 24, 32 bytes para diferentes tamaños de clave).
(matriz de bytes, 16 bytes)
(uno de CBC, CFB, CTS, ECB, OFB)
(Uno de ANSIX923, ISO10126, Ninguno, PKCS7, Zeros)
fuente
KeySize
arregló para mí de inmediato. Oh, las peculiaridades de .NET :-(Mi problema fue que la contraseña de cifrado no coincidía con la contraseña de descifrado ... así que arrojó este error ... un poco engañoso.
fuente
La solución que solucionó la mía fue que, sin darme cuenta, apliqué diferentes claves a los métodos de cifrado y descifrado.
fuente
Me encontré con este error al intentar pasar una ruta de archivo no cifrada al método Decrypt. La solución fue verificar si el archivo pasado está cifrado primero antes de intentar descifrar
fuente
Otro escenario, nuevamente en beneficio de las personas que buscan.
Para mí, este error ocurrió durante el método Dispose () que enmascara un error anterior no relacionado con el cifrado.
Una vez que se solucionó el otro componente, esta excepción desapareció.
fuente
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 modificaba manualmente.
La solución para mí fue colocar un
Como dije, mi error de relleno fue porque estaba escribiendo manualmente sobre el texto descifrado usando el bloc de notas. Puede que mi respuesta pueda guiarte hacia tu solución.
fuente
Yo tenía 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 binarios (1000). Al recuperar los datos de la base de datos, descifraría estos 1000 bytes, mientras que en realidad había 400 bytes. Entonces, al eliminar los ceros finales (600) del resultado, se solucionó el problema.
fuente
Tuve este error y estaba configurando explícitamente el tamaño del bloque:
aesManaged.BlockSize = 128;
Una vez que eliminé eso, funcionó.
fuente
Tuve el mismo problema al intentar portar un programa Go a C #. Esto significa que ya se han cifrado muchos datos con el programa Go. Estos datos ahora deben descifrarse con C #.
La solución final fue
PaddingMode.None
o más bienPaddingMode.Zeros
.Los métodos criptográficos en Go:
... y ...
Ahora, descifrado en C #:
¿Cómo se puede explicar el problema del acolchado? Justo antes de la encriptación, el programa Go comprueba el relleno:
La parte importante es esta:
Se crea una nueva matriz con una longitud adecuada, de modo que la longitud sea un múltiplo del tamaño del bloque. Esta nueva matriz está llena de ceros. El método de copia luego copia los datos existentes en él. Se garantiza que la nueva matriz sea más grande que los datos existentes. En consecuencia, hay ceros al final de la matriz.
Por lo tanto, el código C # puede usar
PaddingMode.Zeros
. La alternativaPaddingMode.None
simplemente ignora cualquier relleno, que también funciona. Espero que esta respuesta sea útil para cualquiera que tenga que transferir el código de Go a C #, etc.fuente
El cliente me informa del mismo error. Yo personalmente no puedo reprocharlo. Mirando el código de los métodos Encrypt y Decrypt , ambos tienen Padding establecido en PaddingMode.PKCS7 . Descifrar se ve así y no puedo ver el problema con él con respecto a ' FlushFinalBlock '. ¿Podría alguien arrojar algo de luz sobre esto?
fuente
Yo tenía el mismo error. En mi caso, la contraseña dada es mayor que 16 significa que está encriptada, pero mientras me descifro recibo este error. Encriptación:
Descifrado:
fuente