2009-03-02 9 views
26

Estoy intentando que el cifrado/descifrado simple funcione con AesManaged, pero sigo obteniendo una excepción cuando intento cerrar la secuencia de descifrado. La cadena aquí se cifra y descifra correctamente, y luego aparece CryptographicException "El relleno no era válido y no se puede eliminar" después de Console.WriteLine imprime la cadena correcta."El relleno no es válido y no se puede eliminar" con AesManaged

¿Alguna idea?

MemoryStream ms = new MemoryStream(); 
byte[] rawPlaintext = Encoding.Unicode.GetBytes("This is annoying!"); 

using (Aes aes = new AesManaged()) 
{ 
    aes.Padding = PaddingMode.PKCS7; 
    aes.Key = new byte[128/8]; 
    aes.IV = new byte[128/8]; 

    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), 
              CryptoStreamMode.Write)) 
    { 
    cs.Write(rawPlaintext, 0, rawPlaintext.Length); 
    cs.FlushFinalBlock(); 
    } 

    ms = new MemoryStream(ms.GetBuffer()); 
    using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), 
              CryptoStreamMode.Read)) 
    { 
    byte[] rawData = new byte[rawPlaintext.Length]; 
    int len = cs.Read(rawData, 0, rawPlaintext.Length); 
    string s = Encoding.Unicode.GetString(rawData); 
    Console.WriteLine(s); 
    } 
} 

Respuesta

44

El truco es usar MemoryStream.ToArray(). También cambié su código para que use el CryptoStream para escribir, tanto en encriptación como en descifrado. Y no es necesario que llame al CryptoStream.FlushFinalBlock() explícitamente, porque lo tiene en una declaración using(), y ese color ocurrirá en Dispose(). El siguiente funciona para mi.

byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!"); 

using (Aes aes = new AesManaged()) 
{ 
    aes.Padding = PaddingMode.PKCS7; 
    aes.KeySize = 128;   // in bits 
    aes.Key = new byte[128/8]; // 16 bytes for 128 bit encryption 
    aes.IV = new byte[128/8]; // AES needs a 16-byte IV 
    // Should set Key and IV here. Good approach: derive them from 
    // a password via Cryptography.Rfc2898DeriveBytes 
    byte[] cipherText= null; 
    byte[] plainText= null; 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(rawPlaintext, 0, rawPlaintext.Length); 
     } 

     cipherText= ms.ToArray(); 
    } 


    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(cipherText, 0, cipherText.Length); 
     } 

     plainText = ms.ToArray(); 
    } 
    string s = System.Text.Encoding.Unicode.GetString(plainText); 
    Console.WriteLine(s); 
} 

Además, supongo que sabe que tendrá que establecer explícitamente la Mode de la instancia AesManaged, y el uso System.Security.Cryptography.Rfc2898DeriveBytes para derivar la clave y el IV de una contraseña y sal.

ver también:
- AesManaged

+4

Tuve el mismo problema, pero usando RijndaelManaged (también simétrico) y no tenía idea de lo que estaba sucediendo. Resulta que 'MemoryStream.GetBuffer()' obtenía una * versión * no eliminada * de los datos, y la mayoría de los bloques finales de datos eran nulos, lo que estaba jugando con mi relleno. 'MemoryStream.ToArray()' obtiene la matriz real. Muchas gracias por esta solución! – Codesleuth

+0

Esta es la implementación mejor/más pequeña que he visto hasta ahora. – tmanthey

+1

Buena llamada en 'Dispose'. Estaba llamando 'ms.ToArray()' antes de eliminar CryptoStream. Moviendo esa línea fuera del uso lo arregló para mí. – cadrell0

1

byte [] rawData = new byte [rawPlaintext.Length];

Necesita leer la longitud del búfer, que probablemente incluya el relleno necesario (IIRC, hace unos años).

21

Esta excepción puede ser causado por un desajuste de cualquiera de una serie de parámetros de cifrado.

Utilicé la interfaz Security.Cryptography.Debug para rastrear todos los parámetros utilizados en los métodos de cifrado/descifrado.

Finalmente descubrí que mi problema era que configuré la propiedad KeySize después de configurar Key, lo que causaba que la clase regenerara una clave aleatoria y no usara la clave que había sido configurada inicialmente.

+4

Mi problema también fue configurar KeySize después de configurar la clave, ¡Gracias! –

+2

+1 Muchas gracias, te votaría 100 veces si pudiera. Pasé más de un día tratando de descubrir por qué no podía descifrar correctamente y resultó que estaba configurando el tamaño de la clave después de la clave en el código. – LeopardSkinPillBoxHat

+0

Gracias, esto resolvió mi problema –

1

Nadie respondió, que en realidad MemoryStream.GetBuffer devuelve el búfer asignado, no los datos reales en este búfer. En este caso, devuelve un búfer de 256 bytes, mientras que contiene solo 32 bytes de datos cifrados.

Cuestiones relacionadas