Wypełnienie jest nieprawidłowe i nie można go usunąć?

126

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

}
Brązowa miłość
źródło
12
Czy możesz spróbować, jawnie ustawiając tryb dopełniania, aby był identyczny zarówno dla szyfrowania, jak i deszyfrowania, aby był indentyczny. Na przykład: alg.Padding = PaddingMode.NONE;
NetSquirrel,
Jak wygląda metoda Encrypt ()?
csharptest.net
1
Dzięki chłopaki, że zadziałało.
Brown Love
2
@NetSquirrel: dziękuję za przypomnienie dotyczące PaddingMode.NONE. To wyciąga mnie z tego błędu (do innego) ... Robiąc AES zarówno w Javie, jak i C #, a teraz nie wiem, dlaczego C # narzeka na wypełnienie Java, chociaż oba używają PKCS # 7
Hoàng Long

Odpowiedzi:

81

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.

Rossum
źródło
7
jak jawnie ustawić dopełnienie?
Ahmad Hajjar
7
Dziękuję, znalazłem rj.Padding = PaddingMode.none; :)
Ahmad Hajjar
7
@AhmadHajjar Żadne wypełnienie nie ma wpływu na bezpieczeństwo, nie używaj go.
deviantfan
1
Cześć, wyraźnie ustawiłem dopełnienie, ale nie działa. Nie wiem, jakie kroki zrobiłem źle. Proszę pomóż. alg.Padding = PaddingMode.PKCS7;
Johnny
21
Zdaję sobie sprawę, że to stary wątek. Ale dla odwiedzających, pamiętaj, aby opróżnić ostatni blok podczas szyfrowania danych.
Markus
53

Upewnij się, że klucze używane do szyfrowania i odszyfrowywaniatakie 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:

Wypełnienie jest nieprawidłowe i nie można go usunąć

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 ivi keydostarczenia przez dzwoniącego.

atconway
źródło
Ta wskazówka była bardzo przydatna, ponieważ czasami klucze są przechowywane w pliku app.config i zawsze musimy mieć pewność, że klucze używane do szyfrowania są takie same, jak używane do odszyfrowania.
Mário Meyrelles
@atconway Czy możesz rzucić okiem na moje pytanie? Mam podobny problem, ale w C ++ / CLI: stackoverflow.com/questions/57139447/ ...
Simple
1
Sugerowałbym, że w codziennym użytkowaniu jest to prawdopodobnie najbardziej prawdopodobny powód, dla którego ludzie napotkają ten błąd. Zwłaszcza jeśli nie bawisz się w ustawieniach dopełnienia.
Dan
28

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ć.

HockeyJ
źródło
Zgadzam się, zdarzyło mi się to samo, sprawdzając odszyfrowanie danych wejściowych PRZED wykonaniem innych kontroli. Otrzymywałem 1 bajt więcej niż zakodowałem ...
Andrea Antonangeli,
Winowajcą był również dla mnie pusty sznurek.
dotNET,
W moim przypadku hasło nie zostało ustawione (tak, wiem), ale ta odpowiedź skierowała mnie we właściwym kierunku.
Jim
2
Mój problem polegał na tym, że ciąg do odszyfrowania był konwertowany na małe litery, zanim spróbowałem go odszyfrować. Miałem obsesję na punkcie wyściółki, szyfrów i tym podobnych rzeczy, ale okazało się, że to po prostu zły wpis. Czasami wystarczy cofnąć się o krok!
Tom Gerken
15

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.

figolu
źródło
1
Dlaczego mówisz, że to źle? Kod do Stream.Close()połączeń this.Dispose(true). Kod dla CryptoStream.Dispose(bool):if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
Kevin Doyon
1
To rozwiązało mój problem. Prawidłowo pozbyłem się cryptoStream, ale wezwanie do usuwania nastąpiło „za późno”, tak jak mówisz. Spowodowało to błąd „nieprawidłowego wypełnienia”, zgodnie z opisem. Dodając cryptoStream.FlushFinalBlock (), naprawiono błąd nieprawidłowego wypełnienia. Dzięki!
Daniel Lambert
14

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

  1. Zmień klasę algorytmu. Zastąp RijndaelManagedklasęAESManaged jedną.
  2. Nie ustawiaj jawnie KeySizeklasy 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ć:

  • Klucz
    (tablica bajtów, długość musi wynosić dokładnie 16, 24, 32 bajty dla różnych rozmiarów klucza).
  • IV
    (tablica bajtów, 16 bajtów)
  • CipherMode
    (jeden z CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (jeden z ANSIX923, ISO10126, brak, PKCS7, Zeros)
Jasio
źródło
3
Brak jednoznacznego ustawienia KeySizenaprawił to od razu. Och, dziwactwa .NET :-(
John
Zauważ, że wydaje się to być regresją w samym .NET Framework. Mam kod, który działał z RijndaelManaged, ale przestał działać, a po prostu zmieniając go na AesManaged / AesCryptoServiceProvider, działa ponownie. Nie miałem nawet żadnego kodu jawnie ustawiającego KeySize. Więc jeśli cię to ugryzie, poczuj się lepiej - wina może nie leżeć po twojej stronie, ale po samym .NET Framework.
Usas
6

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.

ecklerpa
źródło
Właściwie to prawda, że ​​używamy PaddingMode.PKCS7 do szyfrowania i odszyfrowywania, ale otrzymałem ten sam komunikat o błędzie. Mamy również środowisko Stage i Dev z różnymi kluczowymi wartościami. Kiedy użyłem właściwego klucza specyficznego dla środowiska - ten wyjątek został rozwiązany ...
Major
Chociaż wszystkie powyższe odpowiedzi są dobre i musisz użyć tego samego wypełnienia dla opcji Szyfruj i odszyfruj (żadna NIE jest zalecana!), W rzeczywistości ta odpowiedź również może być prawdziwa. Kiedy użyłem odpowiedniego klucza specyficznego dla środowiska, wyjątek „System.Security.Cryptography.CryptographicException: Padding jest nieprawidłowy i nie można go usunąć”. został rozwiązany. Więc tak, może to być mylące.
Major
Jeśli przez „passPhrase” mówisz o dokładnej wartości do zaszyfrowania / odszyfrowania (nie jest to problem z użyciem niewłaściwego klucza), to tak, to był mój problem. Mój przypadek polegał na tym, że oryginalna zaszyfrowana wartość była dłuższa niż zezwalało pole w mojej tabeli bazy danych, więc została obcięta, aby pasowała bez mojej wiedzy. Następnie podczas odszyfrowywania tej obciętej wartości został zgłoszony ten wyjątek.
David Gunderson
2

Rozwiązaniem, które naprawiło moje, było to, że nieumyślnie zastosowałem różne klucze do metod szyfrowania i deszyfrowania.

Rondakay
źródło
1

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

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}
przydatne
źródło
1
Rzucam wyzwanie każdemu tchórzowi Hit and Run w kwestii słuszności tego rozwiązania.
przydatneBee
+1, ponieważ ten wyjątek jest zgłaszany, gdy odszyfrujesz dwukrotnie lub odszyfrujesz coś niezaszyfrowanego. Tak więc odczytałem tę odpowiedź jako „czy jesteś pewien, że dane są rzeczywiście zaszyfrowane?”.
Gerardo Grignoli
0

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ął.

Clay Lenhart
źródło
3
Jaki był poprzedni błąd niezwiązany z szyfrowaniem?
NStuke
0

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

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

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.

webzy
źródło
0

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.

Martijn
źródło
0

Miałem ten błąd i jawnie ustawiałem rozmiar bloku: aesManaged.BlockSize = 128;

Kiedy to usunąłem, zadziałało.

Barry Franklin
źródło
0

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.Nonea raczejPaddingMode.Zeros .

Metody kryptograficzne w Go:

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/sha1"
    "encoding/base64"
    "io/ioutil"
    "log"

    "golang.org/x/crypto/pbkdf2"
)

func decryptFile(filename string, saltBytes []byte, masterPassword []byte) (artifact string) {

    const (
        keyLength         int = 256
        rfc2898Iterations int = 6
    )

    var (
        encryptedBytesBase64 []byte // The encrypted bytes as base64 chars
        encryptedBytes       []byte // The encrypted bytes
    )

    // Load an encrypted file:
    if bytes, bytesErr := ioutil.ReadFile(filename); bytesErr != nil {
        log.Printf("[%s] There was an error while reading the encrypted file: %s\n", filename, bytesErr.Error())
        return
    } else {
        encryptedBytesBase64 = bytes
    }

    // Decode base64:
    decodedBytes := make([]byte, len(encryptedBytesBase64))
    if countDecoded, decodedErr := base64.StdEncoding.Decode(decodedBytes, encryptedBytesBase64); decodedErr != nil {
        log.Printf("[%s] An error occur while decoding base64 data: %s\n", filename, decodedErr.Error())
        return
    } else {
        encryptedBytes = decodedBytes[:countDecoded]
    }

    // Derive key and vector out of the master password and the salt cf. RFC 2898:
    keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
    keyBytes := keyVectorData[:keyLength/8]
    vectorBytes := keyVectorData[keyLength/8:]

    // Create an AES cipher:
    if aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes); aesErr != nil {
        log.Printf("[%s] Was not possible to create new AES cipher: %s\n", filename, aesErr.Error())
        return
    } else {

        // CBC mode always works in whole blocks.
        if len(encryptedBytes)%aes.BlockSize != 0 {
            log.Printf("[%s] The encrypted data's length is not a multiple of the block size.\n", filename)
            return
        }

        // Reserve memory for decrypted data. By definition (cf. AES-CBC), it must be the same lenght as the encrypted data:
        decryptedData := make([]byte, len(encryptedBytes))

        // Create the decrypter:
        aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, vectorBytes)

        // Decrypt the data:
        aesDecrypter.CryptBlocks(decryptedData, encryptedBytes)

        // Cast the decrypted data to string:
        artifact = string(decryptedData)
    }

    return
}

... i ...

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/sha1"
    "encoding/base64"
    "github.com/twinj/uuid"
    "golang.org/x/crypto/pbkdf2"
    "io/ioutil"
    "log"
    "math"
    "os"
)

func encryptFile(filename, artifact string, masterPassword []byte) (status bool) {

    const (
        keyLength         int = 256
        rfc2898Iterations int = 6
    )

    status = false
    secretBytesDecrypted := []byte(artifact)

    // Create new salt:
    saltBytes := uuid.NewV4().Bytes()

    // Derive key and vector out of the master password and the salt cf. RFC 2898:
    keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
    keyBytes := keyVectorData[:keyLength/8]
    vectorBytes := keyVectorData[keyLength/8:]

    // Create an AES cipher:
    if aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes); aesErr != nil {
        log.Printf("[%s] Was not possible to create new AES cipher: %s\n", filename, aesErr.Error())
        return
    } else {

        // CBC mode always works in whole blocks.
        if len(secretBytesDecrypted)%aes.BlockSize != 0 {
            numberNecessaryBlocks := int(math.Ceil(float64(len(secretBytesDecrypted)) / float64(aes.BlockSize)))
            enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
            copy(enhanced, secretBytesDecrypted)
            secretBytesDecrypted = enhanced
        }

        // Reserve memory for encrypted data. By definition (cf. AES-CBC), it must be the same lenght as the plaintext data:
        encryptedData := make([]byte, len(secretBytesDecrypted))

        // Create the encrypter:
        aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, vectorBytes)

        // Encrypt the data:
        aesEncrypter.CryptBlocks(encryptedData, secretBytesDecrypted)

        // Encode base64:
        encodedBytes := make([]byte, base64.StdEncoding.EncodedLen(len(encryptedData)))
        base64.StdEncoding.Encode(encodedBytes, encryptedData)

        // Allocate memory for the final file's content:
        fileContent := make([]byte, len(saltBytes))
        copy(fileContent, saltBytes)
        fileContent = append(fileContent, 10)
        fileContent = append(fileContent, encodedBytes...)

        // Write the data into a new file. This ensures, that at least the old version is healthy in case that the
        // computer hangs while writing out the file. After a successfully write operation, the old file could be
        // deleted and the new one could be renamed.
        if writeErr := ioutil.WriteFile(filename+"-update.txt", fileContent, 0644); writeErr != nil {
            log.Printf("[%s] Was not able to write out the updated file: %s\n", filename, writeErr.Error())
            return
        } else {
            if renameErr := os.Rename(filename+"-update.txt", filename); renameErr != nil {
                log.Printf("[%s] Was not able to rename the updated file: %s\n", fileContent, renameErr.Error())
            } else {
                status = true
                return
            }
        }

        return
    }
}

Teraz odszyfrowanie w C #:

public static string FromFile(string filename, byte[] saltBytes, string masterPassword)
{
    var iterations = 6;
    var keyLength = 256;
    var blockSize = 128;
    var result = string.Empty;
    var encryptedBytesBase64 = File.ReadAllBytes(filename);

    // bytes -> string:
    var encryptedBytesBase64String = System.Text.Encoding.UTF8.GetString(encryptedBytesBase64);

    // Decode base64:
    var encryptedBytes = Convert.FromBase64String(encryptedBytesBase64String);
    var keyVectorObj = new Rfc2898DeriveBytes(masterPassword, saltBytes.Length, iterations);
    keyVectorObj.Salt = saltBytes;
    Span<byte> keyVectorData = keyVectorObj.GetBytes(keyLength / 8 + blockSize / 8);
    var key = keyVectorData.Slice(0, keyLength / 8);
    var iv = keyVectorData.Slice(keyLength / 8);

    var aes = Aes.Create();
    aes.Padding = PaddingMode.Zeros;
    // or ... aes.Padding = PaddingMode.None;
    var decryptor = aes.CreateDecryptor(key.ToArray(), iv.ToArray());
    var decryptedString = string.Empty;

    using (var memoryStream = new MemoryStream(encryptedBytes))
    {
        using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
        {
            using (var reader = new StreamReader(cryptoStream))
            {
                decryptedString = reader.ReadToEnd();
            }
        }
    }

    return result;
}

Jak wyjaśnić problem z wypełnieniem? Tuż przed zaszyfrowaniem program Go sprawdza wypełnienie:

// CBC mode always works in whole blocks.
if len(secretBytesDecrypted)%aes.BlockSize != 0 {
    numberNecessaryBlocks := int(math.Ceil(float64(len(secretBytesDecrypted)) / float64(aes.BlockSize)))
    enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
    copy(enhanced, secretBytesDecrypted)
    secretBytesDecrypted = enhanced
}

Ważna część jest taka:

enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
copy(enhanced, secretBytesDecrypted)

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. Alternatywa PaddingMode.Nonepo 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.

SommerEngineering
źródło
0

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?

public string Decrypt(string cipherText)
{
  if (string.IsNullOrEmpty(cipherText))
    return "";
  string result;
  Encoding byteEncoder = Encoding.Default;

  byte[] rijnKey = byteEncoder.GetBytes(Password);
  byte[] rijnIv = byteEncoder.GetBytes(InitialVector);
  RijndaelManaged rijn = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

  using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
  {
    using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijnKey, rijnIv))
    {
      using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
      {
                    using (StreamReader swDecrypt = new StreamReader(csDecrypt))
                    {
                        result = swDecrypt.ReadToEnd();
                    }
                }
    }
  }
  rijn.Clear();      
  return result.Replace("\0", "");
}
Alexander
źródło
0

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:

string keyString = "CDFUYP@ssw0rd123";
            var key = Encoding.UTF8.GetBytes(keyString);            
            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }                          
                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        var encryptedString = Convert.ToBase64String(result);
                        var decryptedString = Decrypt(encryptedString);
                        if (decryptedString == null)
                        {
                            return null;
                        }
                        return encryptedString;

                    }
                }

Deszyfrowanie:

 string keyString = "CDFUYP@ssw0rd123";
            var fullCipher = Convert.FromBase64String(cipherText);
            var iv = new byte[16];
            var cipher = new byte[16];
            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
sundarraj
źródło
Cześć @sundarraj, czy to jest pytanie?
Tiago Martins Peres 李大仁