2009-03-02 7 views
26

J'essaye d'obtenir le cryptage/décryptage simple fonctionnant avec AesManaged, mais je continue à obtenir une exception en essayant de fermer le flux de déchiffrement. La chaîne ici est cryptée et décryptée correctement, et puis j'obtiens le CryptographicException "Padding était invalide et ne peut pas être enlevé" après Console.WriteLine imprime la chaîne correcte."Le remplissage est invalide et ne peut pas être retiré" using AesManaged

Des idées?

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

Répondre

44

L'astuce consiste à utiliser MemoryStream.ToArray(). J'ai également changé votre code afin qu'il utilise le CryptoStream pour écrire, à la fois dans le cryptage et le décryptage. Et vous n'avez pas besoin d'appeler le CryptoStream.FlushFinalBlock() explicitement, parce que vous l'avez dans une instruction using(), et ce flush se produira sur Dispose(). Les travaux suivants pour moi.

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

Aussi, je suppose que vous savez que vous voulez définir explicitement la Mode de l'instance AesManaged, et utiliser System.Security.Cryptography.Rfc2898DeriveBytes pour obtenir la clé et IV à partir d'un mot de passe et le sel.

voir aussi:
- AesManaged

+4

J'ai eu le même problème, mais en utilisant RijndaelManaged (également symétrique) et n'avais aucune idée de ce qui se passait. Il s'avère que 'MemoryStream.GetBuffer()' obtenait une version * non vidée * des données, et la plupart des derniers blocs de données étaient null, ce qui perturbait mon remplissage. 'MemoryStream.ToArray()' obtient le tableau réel. Merci beaucoup pour cette solution! – Codesleuth

+0

C'est la meilleure/la plus petite implémentation que j'ai vue jusqu'ici. – tmanthey

+1

Bon appel sur 'Dispose'. J'appelais 'ms.ToArray()' avant de disposer de CryptoStream. Déplacer cette ligne en dehors de l'utilisation l'a corrigé pour moi. – cadrell0

1

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

Vous devez lire la longueur du tampon, qui inclut probablement le rembourrage nécessaire (IIRC, été quelques années).

21

Cette exception peut être causée par un déséquilibre entre l'un quelconque d'un certain nombre de paramètres de chiffrement.

J'ai utilisé l'interface Security.Cryptography.Debug pour tracer tous les paramètres utilisés dans les méthodes de cryptage/décryptage. Finalement, j'ai découvert que mon problème était que j'ai défini la propriété KeySize après avoir défini le Key, ce qui a obligé la classe à régénérer une clé aléatoire sans utiliser la clé initialement configurée.

+4

Mon problème était aussi de régler KeySize après avoir réglé la clé, merci! –

+2

+1 Merci beaucoup, je vous voterais 100 fois si je le pouvais. J'ai passé plus d'une journée à essayer de comprendre pourquoi je ne pouvais pas déchiffrer correctement et il s'est avéré que je fixais la taille de la clé après la clé dans le code. – LeopardSkinPillBoxHat

+0

Merci, cela a résolu mon problème –

1

Personne n'a répondu que MemoryStream.GetBuffer renvoie le tampon alloué, pas les données réelles dans ce tampon. Dans ce cas, il renvoie un tampon de 256 octets, alors qu'il ne contient que 32 octets de données chiffrées.