2011-12-20 53 views
66

Ho cercato online cosa significhi questa eccezione in relazione al mio programma ma non riesco a trovare una soluzione o il motivo per cui sta accadendo al mio programma specifico. Ho utilizzato l'esempio fornito il mio msdn per crittografare e decifrare un XmlDocument usando l'algoritmo Rijndael. La crittografia funziona bene, ma quando provo a decifrare, ottengo la seguente eccezione:Il riempimento non è valido e non può essere rimosso?

Padding is invalid and cannot be removed

Qualcuno può dirmi cosa posso fare per risolvere questo problema? Il mio codice qui sotto è dove ottengo la chiave e altri dati. Se il cryptoMode è falso, chiamerà il metodo decrypt, che è dove si verifica l'eccezione:

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

} 
+9

Puoi fare un tentativo impostando esplicitamente la modalità di riempimento in modo identico sia per la crittografia sia per la decifratura per essere indentici. Ad esempio: alg.Padding = PaddingMode.NONE; – NetSquirrel

+0

Che aspetto ha il metodo Encrypt()? –

+0

Grazie ragazzi che hanno funzionato. –

risposta

48

Rijndael/AES è un cifrario a blocchi. Crittografa i dati in blocchi da 128 bit (16 caratteri). Cryptographic padding viene utilizzato per assicurarsi che l'ultimo blocco del messaggio sia sempre della dimensione corretta.

Il metodo di decrittografia si aspetta qualsiasi sia il suo riempimento predefinito e non lo trova. Come dice @NetSquirrel, è necessario impostare in modo esplicito il padding per la crittografia e la decrittografia. A meno che tu non abbia una ragione per fare diversamente, usa l'imbottitura PKCS # 7.

+4

come impostare il padding in modo esplicito ?? –

+2

Grazie, l'ho trovato rj.Padding = PaddingMode.none; :) –

+6

@AhmadHajjar Nessuna spaziatura ha implicazioni sulla sicurezza, non usarla. – deviantfan

31

Assicurarsi che i tasti da utilizzare per cifrare e decifrare sono lo stesso. Il metodo di riempimento, anche se non impostato in modo esplicito, dovrebbe comunque consentire una corretta decrittazione/crittografia (se non impostato saranno uguali). Tuttavia, se per qualche motivo si utilizza un diverso insieme di chiavi per la decodifica da quella utilizzata per la cifratura si sarà ottenere questo errore:

Padding is invalid and cannot be removed

Se si utilizza qualche algoritmo per generare dinamicamente le chiavi che non funzionano. Devono essere uguali sia per la crittografia sia per la decrittografia. Un modo comune è che il chiamante fornisca le chiavi nel costruttore della classe dei metodi di crittografia, per impedire che il processo di crittografia/decrittografia abbia una mano nella creazione di questi elementi. Si concentra sull'attività in corso (crittografia e decrittografia dei dati) e richiede che il iv e il key vengano forniti dal chiamante.

+0

Questo suggerimento è stato molto utile, perché a volte le chiavi sono memorizzate su app.config e dobbiamo sempre essere sicuri che le chiavi utilizzate per cifrare siano le stesse utilizzate per decodificare. –

20

Per il beneficio della ricerca di persone, può essere utile verificare che l'input sia decodificato. Nel mio caso, le informazioni inviate per la decrittografia sono state (erroneamente) entrate come una stringa vuota. Ha provocato l'errore di riempimento.

Questo può riferirsi alla risposta di Rossum, ma ho pensato che fosse degno di nota.

+0

Sono d'accordo, mi è successo lo stesso, verificando che l'input sia stato decodificato PRIMA di fare altri controlli. Avevo 1 byte in più di quello che ho codificato ... –

+0

Una stringa vuota era il colpevole anche per me. – dotNET

+0

Il mio caso era la passphrase non impostata (sì, lo so), ma questa risposta mi ha portato nella giusta direzione. – Jim

0

Un altro scenario, ancora a beneficio delle persone che cercano.

Per me questo errore si è verificato durante il metodo Dispose() che ha mascherato un errore precedente non correlato alla crittografia.

Una volta risolto l'altro componente, questa eccezione è scomparsa.

+1

Qual era l'errore precedente non correlato alla crittografia? – NStuke

0

Ho riscontrato questo errore di riempimento quando avrei modificato manualmente le stringhe crittografate nel file (utilizzando Blocco note) perché volevo testare come si comporterebbe la funzione di decrittografia se il mio contenuto crittografato fosse stato modificato manualmente.

La soluzione per me è stato quello di mettere un

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

Come ho detto il mio errore imbottitura era perché stavo scrivendo manualmente sul testo decifrato utilizzando il Blocco note. Potrebbe essere la mia risposta potrebbe guidarti alla tua soluzione.

5

Un tempo di combattimento, ho finalmente risolto il problema.
(Nota:. Io uso standard AES come algoritmo simmetrico Questa risposta può non adatto per tutti.)

  1. cambiare la classe algoritmo. Sostituire la classe RijndaelManaged in AESManaged una.
  2. Non impostare esplicitamente la classe dell'algoritmo KeySize, lasciati predefiniti.
    (questo è il passo molto importante Penso che ci sia un bug in proprietà KeySize..)

Ecco una lista che si desidera controllare quale argomento si potrebbe avere perso:

  • chiave
    (array di byte, lunghezza deve essere esattamente uno di 16, 24, 32 byte per diverse dimensioni chiave.)
  • IV
    (array di byte, 16 byte)
  • CipherMode
    (Una delle CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (Uno dei ANSIX923, ISO10126, None, PKCS7, Zeri)
+0

Grazie Matt per correggere la mia povera grammatica inglese. – Johnny

+0

L'impostazione non esplicita di 'KeySize' ha risolto il problema immediatamente. Oh le stranezze di .NET :-( – john

4

Se la stessa di inizializzazione chiave e il vettore è utilizzato per la codifica e la decodifica, questo problema non deriva dalla decodifica dei dati ma dalla codifica dei dati.

Dopo aver chiamato il metodo Write su un oggetto CryptoStream, è necessario chiamare SEMPRE il metodo FlushFinalBlock prima del metodo Close.

documentazione MSDN sul metodo CryptoStream.FlushFinalBlock dice:
"Chiamando il metodo Close chiamerà FlushFinalBlock ..."
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs.110).aspx
Questo è sbagliato. La chiamata al metodo Close chiude semplicemente CryptoStream e il flusso di output.
Se non si chiama FlushFinalBlock prima di Chiudi dopo aver scritto i dati da crittografare, durante la decodifica dei dati, una chiamata al metodo Read o CopyTo sull'oggetto CryptoStream genererà un'eccezione CryptographicException (messaggio: "Padding non è valido e non può essere rimosso").

Questo è probabilmente vero per tutti gli algoritmi di crittografia derivati ​​da SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), anche se ho appena verificato che per AesManaged e un MemoryStream come output Stream.

Quindi, se si riceve questa eccezione CryptographicException sulla decrittografia, leggere il valore della proprietà Lunghezza flusso di output dopo aver scritto i dati da crittografare, quindi chiamare FlushFinalBlock e leggere nuovamente il suo valore. Se è cambiato, sai che chiamare FlushFinalBlock NON è opzionale.

E non è necessario eseguire alcun riempimento a livello di programmazione o scegliere un altro valore di proprietà Padding. Il riempimento è il lavoro del metodo FlushFinalBlock.

.........

osservazione

aggiuntivo per Kevin:

Sì, CryptoStream chiama FlushFinalBlock prima di chiamare Close, ma è troppo tardi: quando CryptoStream Primo metodo viene chiamato, l'uscita flusso è anche chiuso.

Se il flusso di output è un MemoryStream, non è possibile leggere i dati dopo che è stato chiuso. Quindi è necessario chiamare FlushFinalBlock sul tuo CryptoStream prima di utilizzare i dati crittografati scritti su MemoryStream.

Se il flusso di output è un FileStream, le cose vanno peggio perché la scrittura è memorizzata nel buffer. La conseguenza è che gli ultimi byte scritti potrebbero non essere scritti sul file se si chiude il flusso di output prima di chiamare Flush su FileStream. Quindi, prima di chiamare Close su CryptoStream, devi prima chiamare FlushFinalBlock sul tuo CryptoStream e chiamare Flush sul tuo FileStream.

+0

Perché dici che è sbagliato? Il codice per 'Stream.Close()' chiama 'this.Dispose (true)'. Il codice per 'CryptoStream.Dispose (bool)' è: 'if (smaltimento) \t \t { \t \t \t se \t \t \t { \t \t \t \t this.FlushFinalBlock() (this._finalBlockTransformed!); \t \t \t} \t \t \t this._s tream.Close(); \t \t} ' – Kevin

+0

Questo ha risolto il mio problema. Stavo smaltendo correttamente il cryptoStream, ma la chiamata di smaltimento stava avvenendo "troppo tardi", proprio come dici tu. Ciò ha provocato l'errore "padding non valido", come descritto. Aggiungendo cryptoStream.FlushFinalBlock(), l'errore di riempimento non valido è stato risolto. Grazie! –

2

Il mio problema era che la passPhrase della crittografia non corrispondeva alla passPhrase del decrypt ... quindi ha gettato questo errore .. un po 'fuorviante.

+0

In realtà è vero che usiamo PaddingMode.PKCS7 per Encrypt e Decrypt ma ho ricevuto lo stesso messaggio di errore. Inoltre abbiamo l'ambiente Stage e Dev con diversi valori chiave. Quando ho usato la chiave specifica per l'ambiente - questa eccezione è stata risolta ... – Major

+0

Anche se tutte le risposte precedenti sono buone e si deve usare lo stesso padding per Encrypt e Decrypt (nessuno è consigliato!) In realtà questa risposta può anche essere vera . Quando ho usato il corretto -environment specifico - chiave l'eccezione "System.Security.Cryptography.CryptographicException: Padding non è valido e non può essere rimosso." è stato risolto Quindi sì, può essere fuorviante. – Major

0

La soluzione che ha risolto il mio era che avevo inavvertitamente applicato chiavi diverse ai metodi di crittografia e decrittografia.

-1

mi sono imbattuto in questo errore durante il tentativo di superare un percorso di file non criptati alla soluzione Decrypt method.The è stato quello di verificare se il file passato è crittografato prima di tentare di decifrare

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

Sfido qualsiasi Hit e Run Coward sulla validità di questa soluzione. – usefulBee

0

ho avuto la stesso errore. Nel mio caso è stato perché ho archiviato i dati crittografati in un database SQL. La tabella in cui sono memorizzati i dati ha un tipo di dati binario (1000). Quando si recuperano i dati dal database, decrittografano questi 1000 byte, mentre là dove effettivamente 400 byte. Quindi rimuovendo lo zero finale (600) dal risultato ha risolto il problema.

Problemi correlati