2009-03-02 10 views
26

Próbuję uzyskać proste szyfrowanie/deszyfrowanie działające z AesManaged, ale wciąż otrzymuję wyjątek podczas próby zamknięcia strumienia deszyfrowania. Łańcuch tutaj zostanie poprawnie zaszyfrowany i odszyfrowany, a następnie otrzymam komunikat "Wyszarzanie CryptographicException" i nie można go usunąć po tym, jak Console.WriteLine wypisze poprawny ciąg znaków."Padding jest nieprawidłowy i nie można go usunąć" przy użyciu AesManaged

Wszelkie pomysły?

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

Odpowiedz

44

Sztuką jest użycie MemoryStream.ToArray(). Zmieniłem również Twój kod tak, aby korzystał z CryptoStream do zapisu, zarówno w szyfrowaniu, jak i odszyfrowywaniu. I nie musisz wyraźnie wywoływać CryptoStream.FlushFinalBlock(), ponieważ masz go w oświadczeniu using(), a ten kolor pojawi się na Dispose(). Poniższe działa dla mnie.

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

Również Chyba wiesz że chcesz jawnie ustawić Mode instancji AesManaged i używać System.Security.Cryptography.Rfc2898DeriveBytes czerpać klucz i IV z hasłem i solą.

patrz też
- AesManaged

+4

Miałem ten sam problem, ale za pomocą RijndaelManaged (również symetryczny) i nie miałem pojęcia, co się dzieje. Okazuje się, że 'MemoryStream.GetBuffer()' otrzymywał * niezamkniętą * wersję danych, a większość końcowych bloków danych miała wartość zerową, co zakłócało moje dopełnianie. 'MemoryStream.ToArray()' pobiera prawdziwą tablicę. Wielkie dzięki za to rozwiązanie! – Codesleuth

+0

To jest najlepsza/najmniejsza implementacja jaką widziałem do tej pory. – tmanthey

+1

Dobre wezwanie do "Dispose". Nazwałem 'ms.ToArray()' przed usunięciem CryptoStream. Przeniesienie tej linii poza obszar użycia spowodowało dla mnie naprawienie. – cadrell0

1

bajt [] = rawData nowy bajt [rawPlaintext.Length];

Musisz odczytać długość bufora, który prawdopodobnie zawiera niezbędne wypełnienie (IIRC, było kilka lat).

21

Wyjątek może być spowodowane niedopasowaniem jednego szeregu parametrów szyfrowania.

Użyłem interfejsu Security.Cryptography.Debug do śledzenia wszystkich parametrów używanych w metodach szyfrowania/odszyfrowywania.

W końcu dowiedziałem się, że mój problem polegał na tym, że ustawiłem właściwość KeySize po ustawieniu Key, co spowoduje, że klasa będzie generować losowy klucz i nie będzie używać klucza, który początkowo ustawiłem.

+4

Mój problem polegał również na ustawianiu KeySize po ustawieniu klucza, dzięki! –

+2

+1 Dziękuję bardzo, zagłosowałbym na ciebie 100 razy, gdybym mógł. Spędziłem ponad dzień próbując dowiedzieć się, dlaczego nie mogę odszyfrować poprawnie i okazało się, że ustawiłem klucz po kluczu w kodzie. – LeopardSkinPillBoxHat

+0

Dziękuję, to rozwiązało mój problem –

1

Nikt nie odpowiedział, że faktycznie MemoryStream.GetBuffer zwraca przydzielony bufor, a nie prawdziwe dane w tym buforze. W tym przypadku zwraca 256-bajtowy bufor, a zawiera tylko 32 bajty zaszyfrowanych danych.