it-swarm.com.de

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

Ich habe online gesucht, was diese Ausnahme in Bezug auf mein Programm bedeutet, aber ich kann keine Lösung finden oder den Grund finden, warum es mit meinem spezifischen Programm geschieht. Ich habe das Beispiel verwendet, das mein msdn zum Verschlüsseln und Entschlüsseln eines XmlDocuments mithilfe des Rijndael-Algorithmus bereitgestellt hat. Die Verschlüsselung funktioniert gut, 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? Mein Code ist, wo ich den Schlüssel und andere Daten bekomme. Wenn der CryptoMode-Wert false ist, wird die Decrypt-Methode 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);

}
86
Brown Love

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

Ihre Entschlüsselungsmethode erwartet, was auch immer ihre 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. Wenn Sie keinen Grund haben, etwas anderes zu tun, verwenden Sie das PKCS # 7-Padding.

62
rossum

Stellen Sie sicher, dass die Schlüssel, die Sie für Verschlüsseln und Entschlüsseln verwenden, gleich sind . Die Auffüllmethode sollte auch dann, wenn sie nicht explizit festgelegt ist, eine ordnungsgemäße Entschlüsselung/Verschlüsselung zulassen (wenn nicht festgelegt, sind sie gleich). Wenn Sie jedoch aus irgendeinem Grund einen anderen Satz von Schlüsseln für die Entschlüsselung verwenden als für die Verschlüsselung, erhalten Sie wird diesen Fehler:

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 Verschlüsselung und Entschlüsselung gleich sein. Ein üblicher Weg besteht darin, dass der Aufrufer die Schlüssel im Konstruktor der Klasse für Verschlüsselungsverfahren bereitstellt, um zu verhindern, dass der Verschlüsselungs-/Entschlüsselungsprozess bei der Erstellung dieser Elemente eine Rolle spielt. Sie konzentriert sich auf die anstehende Aufgabe (Verschlüsseln und Entschlüsseln von Daten) und erfordert, dass iv und key vom Anrufer bereitgestellt werden.

38
atconway

Zum Nutzen der Suchenden kann es sinnvoll sein, die entschlüsselte Eingabe zu überprüfen. In meinem Fall gingen die zur Entschlüsselung gesendeten Informationen (falsch) als leere Zeichenfolge ein. Es ergab sich ein Padding-Fehler.

Dies mag sich auf die Antwort von rossum beziehen, hielt es jedoch für erwähnenswert.

22
HockeyJ

Nach einer Reihe von Kämpfen habe ich das Problem endlich gelöst.
(Hinweis: Ich verwende Standard-AES als symmetrischen Algorithmus. Diese Antwort ist möglicherweise nicht für jeden geeignet ) 

  1. Ändern Sie die Algorithmusklasse. Ersetzen Sie die RijndaelManaged-Klasse durch eine AESManaged-Klasse. 
  2. Setzen Sie die Variable KeySize der Algorithmusklasse nicht explizit, belassen Sie sie jedoch als Standard.
    (Dies ist der sehr wichtige Schritt. Ich denke, dass in der KeySize-Eigenschaft ein Fehler vorliegt.)

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

  • Schlüssel
    (Byte-Array, Länge muss für eine andere Schlüsselgröße genau 16, 24, 32 Byte sein.) 
  • IV
    (Byte-Array, 16 Byte) 
  • CipherMode
    (Eine von CBC, CFB, CTS, EZB, OFB)
  • PaddingMode
    (Einer von ANSIX923, ISO10126, Keine, PKCS7, Nullen)
9
Johnny

Wenn derselbe Schlüssel und der gleiche Initialisierungsvektor zum Kodieren und Dekodieren verwendet werden, liegt dieses Problem nicht bei der Datendekodierung, sondern bei der Datenkodierung. 

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:
"Beim Aufruf der Close-Methode wird FlushFinalBlock ... aufgerufen."
https://msdn.Microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs.110).aspx
Das ist falsch. Durch das Aufrufen der Close-Methode werden nur CryptoStream und der Ausgabestream geschlossen.
Wenn Sie FlushFinalBlock vor dem Schließen nicht aufrufen, nachdem Sie zu verschlüsselnde Daten geschrieben haben, wird beim Entschlüsseln von Daten beim Aufruf der Read- oder CopyTo-Methode für Ihr CryptoStream-Objekt eine CryptographicException-Ausnahme ausgelöst (Meldung: "Auffüllen ist ungültig und kann nicht entfernt werden "). 

Dies gilt wahrscheinlich für alle Verschlüsselungsalgorithmen, die von SymmetricAlgorithm abgeleitet sind (Aes, DES, RC2, Rijndael, TripleDES), obwohl ich dies gerade für AesManaged und einen MemoryStream als Ausgabestrom verifiziert habe. 

Wenn Sie also diese CryptographicException-Ausnahme beim Entschlüsseln erhalten, lesen Sie den Wert der Stream-Eigenschaften der Ausgabedatei nach dem Schreiben der zu verschlüsselnden Daten. 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. 

Sie müssen keine Auffüllung programmgesteuert durchführen oder einen anderen Padding-Eigenschaftswert auswählen. Die Auffüllung ist ein FlushFinalBlock-Methodenjob. 

......... 

Zusätzliche Anmerkung für Kevin: 

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

Wenn es sich bei Ihrem Ausgabestrom um einen MemoryStream handelt, können Sie die Daten nach dem Schließen nicht mehr lesen. Sie müssen also FlushFinalBlock auf Ihrem CryptoStream aufrufen, bevor Sie die auf dem MemoryStream geschriebenen verschlüsselten Daten verwenden. 

Wenn es sich bei Ihrem Ausgabestrom um einen FileStream handelt, sind die Dinge noch schlimmer, da das Schreiben gepuffert wird. Die Folge ist, dass die zuletzt geschriebenen Bytes möglicherweise nicht in die Datei geschrieben werden, wenn Sie den Ausgabestrom schließen, bevor Sie Flush in FileStream aufrufen. Bevor Sie also Close auf CryptoStream aufrufen, müssen Sie zuerst FlushFinalBlock für CryptoStream und dann Flush für FileStream aufrufen.

6
figolu

Mein Problem war, dass die PassPhrase der Verschlüsselung nicht mit der PassPhrase des Entschlüsselungsprogramms übereinstimmte.

3
ecklerpa

Meine Lösung bestand darin, dass ich versehentlich verschiedene Schlüssel für Verschlüsselungs- und Entschlüsselungsmethoden verwendet hatte.

1
Rondakay

Ich stieß auf diesen Padding-Fehler, als ich die verschlüsselten Zeichenfolgen in der Datei manuell bearbeiten wollte (mithilfe von Notepad), weil ich testen wollte, wie sich die Entschlüsselungsfunktion verhält, wenn mein verschlüsselter Inhalt manuell geändert wurde.

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

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

Wie ich schon sagte, war mein Auffüllfehler, weil ich über den entschlüsselten Text mit dem Editor manuell eingegeben habe. Meine Antwort könnte Sie zu Ihrer Lösung führen.

0
webzy

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

Die endgültige Lösung war PaddingMode.None bzw. 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
    }
}

Nun 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 das:

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

Ein neues Array wird mit einer geeigneten Länge erstellt, sodass die Länge ein Vielfaches der Blockgröße ist. 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 gibt es am Ende des Arrays Nullen.

Daher kann der C # -Code PaddingMode.Zeros verwenden. Die Alternative PaddingMode.None ignoriert nur das Auffüllen, was auch funktioniert. Ich hoffe, diese Antwort ist hilfreich für alle, die Code von Gehe zu C # usw. portieren müssen.

0

Ich hatte diesen Fehler und stellte explizit die Blocksize ein: aesManaged.BlockSize = 128;

Nachdem ich das entfernt hatte, funktionierte es. 

0
Barry Franklin

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 (1000) Datentyp. Beim Abrufen der Daten aus der Datenbank würden diese 1000 Byte entschlüsselt, während tatsächlich 400 Byte vorhanden waren. Durch das Entfernen der nachgestellten Nullen (600) aus dem Ergebnis wurde das Problem behoben.

0
Martijn

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

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

Ein weiteres Szenario, wieder zum Wohle der Suchenden. 

Für mich ist dieser Fehler während der Dispose () - Methode aufgetreten, die einen vorherigen Fehler ohne Maskierung maskiert hat.

Sobald die andere Komponente behoben wurde, verschwand diese Ausnahme.

0
Clay Lenhart