Szukałem w Internecie, co oznacza ten wyjątek w odniesieniu do mojego programu, ale nie mogę znaleźć rozwiązania ani przyczyny, dla której dzieje się to z moim programem. Korzystałem z przykładu dostarczonego przez mój MSDN do szyfrowania i odszyfrowywania XmlDocument przy użyciu algorytmu Rijndael. Szyfrowanie działa dobrze, ale kiedy próbuję odszyfrować, pojawia się następujący wyjątek:
Wypełnienie jest nieprawidłowe i nie można go usunąć
Czy ktoś może mi powiedzieć, co mogę zrobić, aby rozwiązać ten problem? Mój kod poniżej to miejsce, w którym otrzymuję klucz i inne dane. Jeśli cryptoMode ma wartość false, wywoła metodę decrypt, w której występuje wyjątek:
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);
}
c#
cryptography
Brązowa miłość
źródło
źródło
Odpowiedzi:
Rijndael / AES to szyfr blokowy. Szyfruje dane w blokach 128-bitowych (16 znaków). Dopełnienie kryptograficzne służy do upewnienia się, że ostatni blok wiadomości ma zawsze prawidłowy rozmiar.
Twoja metoda deszyfrowania oczekuje bez względu na domyślne wypełnienie i go nie znajduje. Jak mówi @NetSquirrel, musisz jawnie ustawić dopełnienie zarówno dla szyfrowania, jak i deszyfrowania. Jeśli nie masz powodu, aby postąpić inaczej, użyj dopełnienia PKCS # 7.
źródło
alg.Padding = PaddingMode.PKCS7;
Upewnij się, że klucze używane do szyfrowania i odszyfrowywania są takie same . Metoda wypełniania, nawet jeśli nie jest jawnie ustawiona, powinna nadal umożliwiać prawidłowe odszyfrowanie / szyfrowanie (jeśli nie zostanie ustawiona, będą takie same). Jeśli jednak z jakiegoś powodu używasz innego zestawu kluczy do odszyfrowania niż używany do szyfrowania, pojawi się ten błąd:
Jeśli używasz jakiegoś algorytmu do dynamicznego generowania kluczy, które nie będą działać. Muszą być takie same zarówno w przypadku szyfrowania, jak i deszyfrowania. Jednym z powszechnych sposobów jest udostępnienie przez wywołującego kluczy w konstruktorze klasy metod szyfrowania, aby uniemożliwić procesowi szyfrowania / deszyfrowania udział w tworzeniu tych elementów. Koncentruje się na wykonywanym zadaniu (szyfrowanie i odszyfrowywanie danych) i wymaga dostarczenia
iv
ikey
dostarczenia przez dzwoniącego.źródło
Z korzyścią dla osób wyszukujących warto sprawdzić deszyfrowane dane wejściowe. W moim przypadku informacja wysyłana do odszyfrowania była (błędnie) podawana jako pusty ciąg. Spowodowało to błąd wypełnienia.
Może to odnosić się do odpowiedzi Rossuma, ale pomyślałem, że warto o tym wspomnieć.
źródło
Jeśli ten sam klucz i wektor inicjalizacji są używane do kodowania i dekodowania, problem nie wynika z dekodowania danych, ale z kodowania danych.
Po wywołaniu metody Write na obiekcie CryptoStream należy ZAWSZE wywołać metodę FlushFinalBlock przed metodą Close.
Dokumentacja MSDN dotycząca metody CryptoStream.FlushFinalBlock mówi:
„ Wywołanie metody Close wywoła FlushFinalBlock ... ”
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs .110) .aspx
To jest złe. Wywołanie metody Close po prostu zamyka CryptoStream i strumień wyjściowy.
Jeśli nie wywołasz FlushFinalBlock przed Close po zapisaniu danych do zaszyfrowania, podczas odszyfrowywania danych wywołanie metody Read lub CopyTo w obiekcie CryptoStream spowoduje zgłoszenie wyjątku CryptographicException (komunikat: „Wypełnienie jest nieprawidłowe i nie można go usunąć”).
Prawdopodobnie jest to prawdą dla wszystkich algorytmów szyfrowania pochodzących z SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), chociaż właśnie zweryfikowałem to dla AesManaged i MemoryStream jako strumienia wyjściowego.
Jeśli więc otrzymasz ten wyjątek CryptographicException podczas odszyfrowywania, przeczytaj wartość właściwości Długość strumienia wyjściowego po zapisaniu danych do zaszyfrowania, a następnie wywołaj FlushFinalBlock i ponownie przeczytaj jego wartość. Jeśli się zmieniło, wiesz, że wywołanie FlushFinalBlock NIE jest opcjonalne.
Nie ma też potrzeby programowego wykonywania wypełniania ani wybierania innej wartości właściwości Padding. Dopełnienie to zadanie metody FlushFinalBlock.
.........
Dodatkowa uwaga dla Kevina:
Tak, CryptoStream wywołuje FlushFinalBlock przed wywołaniem Close, ale jest już za późno: gdy wywoływana jest metoda CryptoStream Close, strumień wyjściowy jest również zamykany.
Jeśli strumień wyjściowy to MemoryStream, nie możesz odczytać jego danych po zamknięciu. Musisz więc wywołać FlushFinalBlock na swoim CryptoStream przed użyciem zaszyfrowanych danych zapisanych w MemoryStream.
Jeśli strumień wyjściowy to FileStream, sytuacja jest gorsza, ponieważ zapis jest buforowany. Konsekwencją jest to, że ostatni zapisany bajt może nie zostać zapisany do pliku, jeśli zamkniesz strumień wyjściowy przed wywołaniem Flush w FileStream. Dlatego przed wywołaniem Close na CryptoStream musisz najpierw wywołać FlushFinalBlock na swoim CryptoStream, a następnie wywołać Flush na swoim FileStream.
źródło
Stream.Close()
połączeńthis.Dispose(true)
. Kod dlaCryptoStream.Dispose(bool)
:if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
Kilka dni walk w końcu rozwiązałem problem.
(Uwaga: używam standardowego AES jako algorytmu symetrycznego. Ta odpowiedź może nie być odpowiednia dla wszystkich).
RijndaelManaged
klasęAESManaged
jedną.KeySize
klasy algorytmu, pozostaw je domyślne.(To jest bardzo ważny krok. Myślę, że we właściwości KeySize jest błąd).
Oto lista, którą chcesz sprawdzić, który argument mógłbyś przegapić:
(tablica bajtów, długość musi wynosić dokładnie 16, 24, 32 bajty dla różnych rozmiarów klucza).
(tablica bajtów, 16 bajtów)
(jeden z CBC, CFB, CTS, ECB, OFB)
(jeden z ANSIX923, ISO10126, brak, PKCS7, Zeros)
źródło
KeySize
naprawił to od razu. Och, dziwactwa .NET :-(Mój problem polegał na tym, że hasło szyfrowania nie pasowało do hasła odszyfrowania ... więc spowodowało to błąd ... trochę mylący.
źródło
Rozwiązaniem, które naprawiło moje, było to, że nieumyślnie zastosowałem różne klucze do metod szyfrowania i deszyfrowania.
źródło
Natknąłem się na ten błąd podczas próby przekazania niezaszyfrowanej ścieżki do pliku do metody Decrypt.Rozwiązaniem było sprawdzenie, czy przekazany plik jest najpierw zaszyfrowany przed próbą odszyfrowania
źródło
Inny scenariusz, znowu na korzyść osób poszukujących.
U mnie ten błąd wystąpił podczas metody Dispose (), która maskowała poprzedni błąd niezwiązany z szyfrowaniem.
Po naprawieniu drugiego komponentu ten wyjątek zniknął.
źródło
Napotkałem ten błąd wypełniania, gdy ręcznie edytować zaszyfrowane ciągi w pliku (za pomocą notatnika), ponieważ chciałem przetestować, jak zachowa się funkcja odszyfrowywania, jeśli moja zaszyfrowana zawartość zostanie zmieniona ręcznie.
Rozwiązaniem dla mnie było umieszczenie pliku
Tak jak powiedziałem, mój błąd wypełnienia był taki, że ręcznie wpisałem odszyfrowany tekst za pomocą notatnika. Może moja odpowiedź poprowadzi Cię do rozwiązania.
źródło
Miałem ten sam błąd. W moim przypadku to dlatego, że zapisałem zaszyfrowane dane w bazie danych SQL. Tabela, w której przechowywane są dane, ma binarny (1000) typ danych. Podczas pobierania danych z bazy danych odszyfrowałoby te 1000 bajtów, podczas gdy w rzeczywistości było 400 bajtów. Usunięcie końcowych zer (600) z wyniku rozwiązało problem.
źródło
Miałem ten błąd i jawnie ustawiałem rozmiar bloku:
aesManaged.BlockSize = 128;
Kiedy to usunąłem, zadziałało.
źródło
Miałem ten sam problem podczas próby przeniesienia programu Go do C #. Oznacza to, że wiele danych zostało już zaszyfrowanych programem Go. Te dane muszą teraz zostać odszyfrowane za pomocą C #.
Ostatecznym rozwiązaniem było
PaddingMode.None
a raczejPaddingMode.Zeros
.Metody kryptograficzne w Go:
... i ...
Teraz odszyfrowanie w C #:
Jak wyjaśnić problem z wypełnieniem? Tuż przed zaszyfrowaniem program Go sprawdza wypełnienie:
Ważna część jest taka:
Tworzona jest nowa tablica o odpowiedniej długości, tak aby długość była wielokrotnością rozmiaru bloku. Ta nowa tablica jest wypełniona zerami. Metoda copy kopiuje następnie do niego istniejące dane. Zapewnia się, że nowa tablica jest większa niż istniejące dane. W związku z tym na końcu tablicy znajdują się zera.
W ten sposób kod C # może używać
PaddingMode.Zeros
. AlternatywaPaddingMode.None
po prostu ignoruje wszelkie dopełnienie, które również działa. Mam nadzieję, że ta odpowiedź jest pomocna dla każdego, kto musi przenieść kod z Idź do C # itp.źródło
Klient zgłasza mi ten sam błąd. Osobiście nie mogę tego powtórzyć. Patrząc na kod Szyfruj i Deszyfruj metod, obie mają Dodat zestaw do PaddingMode.PKCS7 . Deszyfrowanie wygląda tak i nie widzę z tym problemu w odniesieniu do „ FlushFinalBlock ”. Czy ktoś mógłby rzucić na to trochę światła?
źródło
Miałem ten sam błąd. W moim przypadku podane hasło jest większe niż 16 oznacza, że jest zaszyfrowane, ale podczas odszyfrowywania otrzymuję ten błąd. Szyfrowanie:
Deszyfrowanie:
źródło