Polsterung ist ungültig und kann nicht entfernt werden?


123

Ich habe online gesucht, was diese Ausnahme in Bezug auf mein Programm bedeutet, kann aber anscheinend keine Lösung finden oder den Grund, warum es mit meinem spezifischen Programm passiert. Ich habe das Beispiel meiner msdn zum Ver- und Entschlüsseln eines XmlDocument mit dem Rijndael-Algorithmus verwendet. Die Verschlüsselung funktioniert einwandfrei, aber wenn ich versuche zu entschlüsseln, erhalte ich die folgende Ausnahme:

Das Auffüllen ist ungültig und kann nicht entfernt werden

Kann mir jemand sagen, was ich tun kann, um dieses Problem zu lösen? In meinem Code unten erhalte ich den Schlüssel und andere Daten. Wenn der cryptoMode false ist, wird die Entschlüsselungsmethode aufgerufen, bei der die Ausnahme auftritt:

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

}

12
Können Sie es versuchen, indem Sie den Auffüllmodus explizit so einstellen, dass er sowohl bei der Verschlüsselung als auch bei der Entschlüsselung identisch ist. Zum Beispiel: alg.Padding = PaddingMode.NONE;
NetSquirrel

Wie sieht die Encrypt () -Methode aus?
csharptest.net

1
Danke Jungs, die funktioniert haben.
Brown Love

2
@ NetSquirrel: Danke für die Erinnerung an PaddingMode.NONE. Es bringt mich aus diesem Fehler heraus (zu einem anderen) ... Ich mache AES sowohl in Java als auch in C # und weiß jetzt nicht, warum C # sich über Java-Padding beschwert, obwohl beide PKCS # 7
Hoàng Long

Antworten:


80

Rijndael / AES ist eine Blockverschlüsselung. Es verschlüsselt Daten in 128-Bit-Blöcken (16 Zeichen). Durch kryptografisches Auffüllen wird sichergestellt, dass der letzte Block der Nachricht immer die richtige Größe hat.

Ihre Entschlüsselungsmethode erwartet, was auch immer die Standardauffüllung ist, und findet sie nicht. Wie @NetSquirrel sagt, müssen Sie die Auffüllung sowohl für die Verschlüsselung als auch für die Entschlüsselung explizit festlegen. Verwenden Sie PKCS # 7-Polsterung, sofern Sie keinen Grund haben, etwas anderes zu tun.


7
Wie wird die Polsterung explizit eingestellt?
Ahmad Hajjar

7
Danke, ich habe es gefunden rj.Padding = PaddingMode.none; :)
Ahmad Hajjar

7
@AhmadHajjar Keine Polsterung hat Auswirkungen auf die Sicherheit. Verwenden Sie sie nicht.
Deviantfan

1
Hallo, ich habe die Polsterung explizit eingestellt, aber nicht funktioniert. Ich weiß nicht, welche Schritte ich falsch gemacht habe. Bitte helfen Sie. alg.Padding = PaddingMode.PKCS7;
Johnny

20
Mir ist klar, dass dies ein alter Thread ist. Stellen Sie jedoch für Besucher sicher, dass Sie den letzten Block leeren, wenn Sie die Daten verschlüsseln.
Markus

51

Stellen Sie sicher , dass die Schlüssel Sie verwenden verschlüsseln und entschlüsseln sind die gleichen . Die Auffüllmethode sollte auch dann, wenn sie nicht explizit festgelegt wurde, eine ordnungsgemäße Entschlüsselung / Verschlüsselung ermöglichen (wenn sie nicht festgelegt ist, sind sie gleich). Wenn Sie jedoch aus irgendeinem Grund einen anderen Schlüsselsatz zur Entschlüsselung verwenden als zur Verschlüsselung, wird folgende Fehlermeldung angezeigt:

Das Auffüllen ist ungültig und kann nicht entfernt werden

Wenn Sie einen Algorithmus verwenden, um dynamisch Schlüssel zu generieren, die nicht funktionieren. Sie müssen für die Ver- und Entschlüsselung gleich sein. Eine übliche Methode besteht darin, dass der Aufrufer die Schlüssel im Konstruktor der Klasse der Verschlüsselungsmethoden bereitstellt, um zu verhindern, dass der Verschlüsselungs- / Entschlüsselungsprozess bei der Erstellung dieser Elemente eine Rolle spielt. Es konzentriert sich auf die jeweilige Aufgabe (Ver- und Entschlüsseln von Daten) und erfordert, dass das ivund keyvom Anrufer bereitgestellt wird.


Dieser Tipp war sehr nützlich, da die Schlüssel manchmal in app.config gespeichert sind und wir immer sicher sein müssen, dass die zum Verschlüsseln verwendeten Schlüssel mit den zum Entschlüsseln verwendeten übereinstimmen.
Mário Meyrelles

@atconway Würde es Ihnen etwas ausmachen, sich meine Frage anzuschauen? Ich habe ein ähnliches Problem, aber in C ++ / CLI: stackoverflow.com/questions/57139447/…
Einfach

Ich würde vorschlagen, dass dies im täglichen Gebrauch wahrscheinlich der wahrscheinlichste Grund ist, warum Menschen auf diesen Fehler stoßen. Vor allem, wenn Sie nicht mit den Polstereinstellungen herumspielen.
Dan

28

Für die Suche kann es sich lohnen, die entschlüsselte Eingabe zu überprüfen. In meinem Fall wurden die zur Entschlüsselung gesendeten Informationen (fälschlicherweise) als leere Zeichenfolge eingegeben. Dies führte zu einem Auffüllfehler.

Dies mag sich auf Rossums Antwort beziehen, hielt es aber für erwähnenswert.


Ich bin damit einverstanden, passierte mir genauso und überprüfte die entschlüsselte Eingabe, bevor andere Überprüfungen durchgeführt wurden. Ich bekam 1 Byte mehr als ich erwartet hatte ...
Andrea Antonangeli

Eine leere Schnur war auch für mich der Schuldige.
dotNET

Mein Fall war, dass die Passphrase nicht festgelegt wurde (ja, ich weiß), aber diese Antwort brachte mich in die richtige Richtung.
Jim

2
Mein Problem war, dass die zu entschlüsselnde Zeichenfolge in Kleinbuchstaben konvertiert wurde, bevor ich versuchte, sie zu entschlüsseln. Ich war besessen von der Polsterung und den Chiffren und all dem Zeug, aber es stellte sich heraus, dass es nur eine schlechte Eingabe war. Manchmal muss man nur einen Schritt zurück machen!
Tom Gerken

15

Wenn für die Codierung und Decodierung derselbe Schlüssel und der gleiche Initialisierungsvektor verwendet werden, liegt dieses Problem nicht bei der Datendecodierung, sondern bei der Datencodierung.

Nachdem Sie die Write-Methode für ein CryptoStream-Objekt aufgerufen haben, müssen Sie IMMER die FlushFinalBlock-Methode vor der Close-Methode aufrufen.

In der MSDN-Dokumentation zur CryptoStream.FlushFinalBlock-Methode heißt es:
"Durch Aufrufen der Close-Methode wird FlushFinalBlock aufgerufen ... "
https://msdn.microsoft.com/de-DE/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs .110) .aspx
Das ist falsch. Durch Aufrufen der Close-Methode werden nur der CryptoStream und der Ausgabestream geschlossen.
Wenn Sie FlushFinalBlock nicht vor dem Schließen aufrufen, nachdem Sie zu verschlüsselnde Daten geschrieben haben, löst ein Aufruf der Read- oder CopyTo-Methode für Ihr CryptoStream-Objekt beim Aufschlüsseln eine CryptographicException-Ausnahme aus (Meldung: "Auffüllen ist ungültig und kann nicht entfernt werden").

Dies gilt wahrscheinlich für alle von SymmetricAlgorithm abgeleiteten Verschlüsselungsalgorithmen (Aes, DES, RC2, Rijndael, TripleDES), obwohl ich dies gerade für AesManaged und einen MemoryStream als Ausgabestream überprüft habe.

Wenn Sie diese CryptographicException-Ausnahme bei der Entschlüsselung erhalten, lesen Sie den Wert Ihrer Ausgabestream-Length-Eigenschaft, nachdem Sie Ihre zu verschlüsselnden Daten geschrieben haben. Rufen Sie dann FlushFinalBlock auf und lesen Sie den Wert erneut. Wenn es sich geändert hat, wissen Sie, dass das Aufrufen von FlushFinalBlock NICHT optional ist.

Außerdem müssen Sie kein Auffüllen programmgesteuert durchführen oder einen anderen Wert für die Padding-Eigenschaft auswählen. Das Auffüllen ist ein FlushFinalBlock-Methodenjob.

.........

Zusätzliche Bemerkung für Kevin:

Ja, CryptoStream ruft FlushFinalBlock auf, bevor Close geschlossen wird, aber es ist zu spät: Wenn die CryptoStream Close-Methode aufgerufen wird, wird auch der Ausgabestream geschlossen.

Wenn Ihr Ausgabestream ein MemoryStream ist, können Sie seine Daten nach dem Schließen nicht mehr lesen. Sie müssen also FlushFinalBlock in Ihrem CryptoStream aufrufen, bevor Sie die im MemoryStream geschriebenen verschlüsselten Daten verwenden können.

Wenn Ihr Ausgabestream ein FileStream ist, sind die Dinge schlechter, weil das Schreiben gepuffert ist. Die Folge ist, dass zuletzt geschriebene Bytes möglicherweise nicht in die Datei geschrieben werden, wenn Sie den Ausgabestream schließen, bevor Sie Flush in FileStream aufrufen. Bevor Sie Close in CryptoStream aufrufen, müssen Sie zuerst FlushFinalBlock in Ihrem CryptoStream aufrufen und dann Flush in Ihrem FileStream aufrufen.


1
Warum sagst du, dass es falsch ist? Der Code für Stream.Close()Anrufe this.Dispose(true). Der Code für CryptoStream.Dispose(bool)ist:if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
Kevin Doyon

1
Dies löste mein Problem. Ich habe den cryptoStream korrekt entsorgt, aber der Entsorgungsaufruf erfolgte "zu spät", genau wie Sie sagen. Dies führte wie beschrieben zu dem Fehler "ungültiges Auffüllen". Durch Hinzufügen von cryptoStream.FlushFinalBlock () wurde der ungültige Auffüllfehler behoben. Vielen Dank!
Daniel Lambert

13

Nach mehreren Kämpfen löste ich endlich das Problem.
(Hinweis: Ich verwende Standard-AES als symmetrischen Algorithmus. Diese Antwort ist möglicherweise nicht für alle geeignet.)

  1. Ändern Sie die Algorithmusklasse. Ersetzen Sie die RijndaelManagedKlasse durch AESManagedeine.
  2. Legen Sie die KeySizeAlgorithmusklasse nicht explizit fest, sondern belassen Sie sie als Standard.
    (Dies ist der sehr wichtige Schritt. Ich denke, es gibt einen Fehler in der KeySize-Eigenschaft.)

Hier ist eine Liste, in der Sie überprüfen möchten, welches Argument Sie möglicherweise übersehen haben:

  • Schlüssel
    (Byte-Array, Länge muss für unterschiedliche Schlüsselgrößen genau 16, 24, 32 Byte betragen.)
  • IV
    (Byte-Array, 16 Byte)
  • CipherMode
    (einer von CBC, CFB, CTS, EZB, OFB)
  • PaddingMode
    (Einer von ANSIX923, ISO10126, None, PKCS7, Zeros)

3
Nicht explizit eingestellt hat KeySizees für mich sofort behoben. Oh die Macken von .NET :-(
John

Beachten Sie, dass dies eine Regression in .NET Framework selbst zu sein scheint. Ich habe Code, der früher mit RijndaelManaged funktioniert hat, aber nicht mehr funktioniert. Durch einfaches Ändern in AesManaged / AesCryptoServiceProvider funktioniert er wieder. Ich hatte nicht einmal einen Code, der die Schlüsselgröße explizit festlegte. Wenn Sie davon gebissen werden, fühlen Sie sich besser - der Fehler liegt möglicherweise nicht bei Ihnen, sondern beim .NET Framework selbst.
Usas

6

Mein Problem war, dass die passPhrase der Verschlüsselung nicht mit der passPhrase der Entschlüsselung übereinstimmte ... also warf es diesen Fehler ... ein wenig irreführend.


Eigentlich verwenden wir PaddingMode.PKCS7 zum Ver- und Entschlüsseln, aber ich habe die gleiche Fehlermeldung erhalten. Wir haben auch eine Stage- und Dev-Umgebung mit unterschiedlichen Schlüsselwerten. Als ich den richtigen Umgebungsschlüssel verwendet habe, wurde diese Ausnahme behoben ...
Major

Obwohl alle oben genannten Antworten gut sind und Sie für das Verschlüsseln und Entschlüsseln dieselbe Auffüllung verwenden müssen (keine wird NICHT empfohlen!), Kann diese Antwort auch wahr sein. Wenn ich die richtige Umgebung verwendet habe, geben Sie die Ausnahme "System.Security.Cryptography.CryptographicException: Padding ist ungültig und kann nicht entfernt werden." wurde gelöst. Also ja, es kann irreführend sein.
Major

Wenn Sie mit "passPhrase" über den genauen Wert zum Ver- / Entschlüsseln sprechen (kein Problem bei der Verwendung des falschen Schlüssels), dann war dies mein Problem. Mein Fall war, dass der ursprünglich verschlüsselte Wert länger war als in meinem Datenbanktabellenfeld zulässig, sodass er so abgeschnitten wurde, dass er passt, ohne dass ich es merkte. Beim Entschlüsseln dieses abgeschnittenen Werts wurde diese Ausnahme ausgelöst.
David Gunderson

2

Die Lösung, die meine behoben hat, war, dass ich versehentlich verschiedene Schlüssel auf Verschlüsselungs- und Entschlüsselungsmethoden angewendet hatte.


1

Ich bin auf diesen Fehler gestoßen, als ich versucht habe, einen unverschlüsselten Dateipfad an die Entschlüsselungsmethode zu übergeben. Die Lösung bestand darin, zu überprüfen, ob die übergebene Datei zuerst verschlüsselt ist, bevor versucht wird, sie zu entschlüsseln

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

1
Ich fordere jeden Hit and Run-Feigling zur Gültigkeit dieser Lösung heraus.
nützlichBee

+1, da diese Ausnahme ausgelöst wird, wenn Sie zweimal oder nicht verschlüsselt etwas entschlüsseln. Also las ich diese Antwort als "Sind Sie sicher, dass die Daten tatsächlich verschlüsselt sind?".
Gerardo Grignoli

0

Ein weiteres Szenario, wiederum zum Nutzen der Suchenden.

Für mich trat dieser Fehler während der Dispose () -Methode auf, die einen früheren Fehler maskierte, der nicht mit der Verschlüsselung zusammenhängt.

Sobald die andere Komponente behoben war, verschwand diese Ausnahme.


3
Was war der vorherige Fehler, der nicht mit der Verschlüsselung zusammenhängt?
NStuke

0

Ich habe diesen Auffüllfehler festgestellt, als ich die verschlüsselten Zeichenfolgen in der Datei manuell bearbeitet habe (mit dem Editor), weil ich testen wollte, wie sich die Entschlüsselungsfunktion verhält, wenn mein verschlüsselter Inhalt manuell geändert wird.

Die Lösung für mich war, eine zu platzieren

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

Wie ich bereits sagte, war mein Auffüllfehler darauf zurückzuführen, dass ich den entschlüsselten Text manuell mit dem Editor eingegeben habe. Vielleicht führt Sie meine Antwort zu Ihrer Lösung.


0

Ich hatte den gleichen Fehler. In meinem Fall lag es daran, dass ich die verschlüsselten Daten in einer SQL-Datenbank gespeichert habe. Die Tabelle, in der die Daten gespeichert sind, hat einen binären Datentyp (1000). Beim Abrufen der Daten aus der Datenbank werden diese 1000 Bytes entschlüsselt, während dort tatsächlich 400 Bytes vorhanden sind. Durch Entfernen der nachgestellten Nullen (600) aus dem Ergebnis wurde das Problem behoben.


0

Ich hatte diesen Fehler und stellte explizit die Blockgröße ein: aesManaged.BlockSize = 128;

Sobald ich das entfernt habe, hat es funktioniert.


0

Ich hatte das gleiche Problem beim Versuch, ein Go-Programm nach C # zu portieren. Dies bedeutet, dass viele Daten bereits mit dem Go-Programm verschlüsselt wurden. Diese Daten müssen jetzt mit C # entschlüsselt werden.

Die endgültige Lösung war PaddingMode.Noneoder eher PaddingMode.Zeros.

Die kryptografischen Methoden in 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
}

... und ...

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

Jetzt Entschlüsselung in 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;
}

Wie kann das Problem mit der Polsterung erklärt werden? Kurz vor der Verschlüsselung überprüft das Go-Programm die Auffüllung:

// 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
}

Der wichtige Teil ist folgender:

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

Ein neues Array mit einer geeigneten Länge wird erstellt, sodass die Länge ein Vielfaches der Blockgröße beträgt. Dieses neue Array ist mit Nullen gefüllt. Die Kopiermethode kopiert dann die vorhandenen Daten hinein. Es wird sichergestellt, dass das neue Array größer als die vorhandenen Daten ist. Dementsprechend befinden sich am Ende des Arrays Nullen.

Somit kann der C # -Code verwendet werden PaddingMode.Zeros. Die Alternative PaddingMode.Noneignoriert einfach jede Polsterung, die auch funktioniert. Ich hoffe, diese Antwort ist hilfreich für alle, die Code von Go to C # usw. portieren müssen.


0

Ich habe den gleichen Fehler vom Kunden gemeldet. Ich persönlich kann es nicht tadeln. Mit Blick auf den Code von Encrypt und Decrypt Methoden, beide haben Padding Satz PaddingMode.PKCS7 . Das Entschlüsseln sieht so aus und ich kann das Problem damit in Bezug auf ' FlushFinalBlock ' nicht erkennen. Könnte jemand bitte etwas Licht ins Dunkel bringen?

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

0

Ich hatte den gleichen Fehler. In meinem Fall ist das angegebene Passwort größer als 16, was bedeutet, dass es verschlüsselt ist, aber während der Entschlüsselung erhalte ich diesen Fehler. Verschlüsselung:

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;

                    }
                }

Entschlüsselung:

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

Hallo @sundarraj, ist das eine Frage?
Tiago Martins Peres 李大仁
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.