2009-03-02 14 views
26

Sto cercando di ottenere una semplice crittografia/decrittografia che funziona con AesManaged, ma continuo a ricevere un'eccezione quando provo a chiudere il flusso di decrittografia. La stringa qui viene crittografata e decrittografata correttamente, quindi viene visualizzato CryptographicException "Padding non valido e non può essere rimosso" dopo che Console.WriteLine stampa la stringa corretta."Padding non valido e non può essere rimosso" utilizzando AesManaged

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

risposta

44

Il trucco è utilizzare MemoryStream.ToArray(). Ho anche modificato il codice in modo che utilizzi lo CryptoStream per scrivere, sia in crittografia che in decrittografia. E non è necessario chiamare lo CryptoStream.FlushFinalBlock() esplicitamente, perché lo hai in una dichiarazione using(), e che lo svuotamento avverrà su Dispose(). Il seguente funziona per me.

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

Inoltre, credo che tu sai che si vuole impostare in modo esplicito la Mode dell'istanza AesManaged, e utilizzare System.Security.Cryptography.Rfc2898DeriveBytes per derivare la chiave e IV da una password e il sale.

vedi anche:
- AesManaged

+4

Ho avuto lo stesso problema, ma utilizzando RijndaelManaged (anche simmetrico) e non avevo idea di cosa stesse succedendo. Si scopre che 'MemoryStream.GetBuffer()' stava ottenendo una * versione non scarica * dei dati, e la maggior parte dei blocchi finali di dati erano nulli, il che stava scherzando con il mio padding. 'MemoryStream.ToArray()' ottiene il vero array. Mille grazie per questa soluzione! – Codesleuth

+0

Questa è l'implementazione migliore/minima che ho visto finora. – tmanthey

+1

Buona chiamata su 'Dispose'. Stavo chiamando 'ms.ToArray()' prima di smaltire CryptoStream. Spostare quella linea al di fuori dell'uso l'ha risolto per me. – cadrell0

1

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

È necessario leggere la lunghezza del buffer, che probabilmente include il padding necessario (IIRC, alcuni anni).

21

Questa eccezione può essere causato da una mancata corrispondenza di uno qualsiasi di una serie di parametri di codifica.

Ho utilizzato l'interfaccia Security.Cryptography.Debug per tracciare tutti i parametri utilizzati nei metodi di crittografia/decrittografia. Finalmente ho scoperto che il mio problema era che ho impostato la proprietà KeySize dopo aver impostato il facendo sì che la classe rigenerasse una chiave casuale e non usasse la chiave inizialmente impostata.

+4

Il mio problema era anche impostare KeySize dopo aver impostato la chiave, Grazie! –

+2

+1 Grazie mille, voterei su 100 volte se potessi. Ho passato più di un giorno a cercare di capire perché non potevo decifrare correttamente e ho scoperto che stavo impostando la dimensione della chiave dopo la chiave nel codice. – LeopardSkinPillBoxHat

+0

Grazie, questo ha risolto il mio problema –

1

Nessuno ha risposto, che in realtà MemoryStream.GetBuffer restituisce il buffer allocato, non i dati reali in questo buffer. In questo caso restituisce un buffer da 256 byte, mentre contiene solo 32 byte di dati crittografati.

Problemi correlati