Wie kann man PKCS7-Padding aus einer AES-verschlüsselten Zeichenfolge hinzufügen/entfernen?

Lesezeit: 8 Minuten

Wie kann man PKCS7 Padding aus einer AES verschlusselten Zeichenfolge hinzufugenentfernen
Ali

Ich versuche, eine Zeichenfolge mit 128-Bit-AES-Verschlüsselung (ECB) zu verschlüsseln/entschlüsseln. Was ich wissen möchte, ist, wie ich die PKCS7-Auffüllung hinzufügen/entfernen kann. Es scheint, dass die Mcrypt-Erweiterung die Verschlüsselung/Entschlüsselung übernehmen kann, aber die Auffüllung muss manuell hinzugefügt/entfernt werden.

Irgendwelche Ideen?

  • Nur eine Anmerkung: Wenn Sie ändern können, verwenden Sie ein anderer Modus als ECB (es ist unsicher).

    – Paulo Ebermann

    6. September 2011 um 18:23 Uhr

  • @Paul Nein, kann nicht geändert werden, davon hängt das System des Kunden ab. Könntest du mich vielleicht mit der Polsterung anleiten?

    – Ali

    6. September 2011 um 18:31 Uhr

  • Verwenden Sie nicht den ECB-Modus. Wenn Ihr Kunde denkt, dass er ECB braucht, liegt er falsch. Verwenden Sie CTR oder CBC, stellen Sie sicher, dass Sie Ihre Chiffretexte authentifizieren.

    – Scott Arciszewski

    29. Juli 2015 um 16:34 Uhr

  • Diese Antwort behandelt das Hinzufügen von Padding zu bereits verschlüsselten Daten: stackoverflow.com/questions/24404770/…

    – rsc

    3. Februar 2021 um 7:07 Uhr

Wie kann man PKCS7 Padding aus einer AES verschlusselten Zeichenfolge hinzufugenentfernen
Paulo Ebermann

Mal sehen. PKCS #7 ist in RFC 5652 (Cryptographic Message Syntax) beschrieben.

Das Auffüllschema selbst ist in Abschnitt angegeben 6.3. Inhaltsverschlüsselungsprozess. Es besagt im Wesentlichen: Hängen Sie so viele Bytes an, wie Sie benötigen, um die angegebene Blockgröße (aber mindestens eines) zu füllen, und jeder von ihnen sollte die Auffülllänge als Wert haben.

Wenn wir uns also das letzte entschlüsselte Byte ansehen, wissen wir, wie viele Bytes entfernt werden müssen. (Man könnte auch überprüfen, ob sie alle den gleichen Wert haben.)

Ich könnte Ihnen jetzt ein paar PHP-Funktionen dafür geben, aber mein PHP ist ein bisschen eingerostet. Machen Sie dies entweder selbst (dann können Sie meine Antwort bearbeiten, um sie hinzuzufügen), oder sehen Sie sich die an von Benutzern beigesteuerte Notizen zur mcrypt-Dokumentation – einige von ihnen handeln vom Padding und stellen eine Implementierung von PKCS #7 Padding bereit.


Schauen wir uns also die an erste Notiz dort im Detail:

<?php

function encrypt($str, $key)
 {
     $block = mcrypt_get_block_size('des', 'ecb');

Dies erhält die Blockgröße des verwendeten Algorithmus. In Ihrem Fall würden Sie verwenden aes oder rijndael_128 anstatt des, nehme ich an (ich habe es nicht getestet). (Stattdessen könntest du einfach nehmen 16 hier für AES, anstatt die Funktion aufzurufen.)

     $pad = $block - (strlen($str) % $block);

Dadurch wird die Polsterungsgröße berechnet. strlen($str) ist die Länge Ihrer Daten (in Bytes), % $block ergibt den Rest modulo $blockdh die Anzahl der Datenbytes im letzten Block. $block - ... gibt also die Anzahl der Bytes an, die benötigt werden, um diesen letzten Block zu füllen (dies ist jetzt eine Zahl zwischen 1 und $blockinklusive).

     $str .= str_repeat(chr($pad), $pad);

str_repeat erzeugt eine Zeichenfolge, die aus einer Wiederholung derselben Zeichenfolge besteht, hier eine Wiederholung der Zeichen gegeben durch $pad, $pad Zeiten, dh eine Zeichenfolge der Länge $padgefüllt mit $pad.
$str .= ... fügt diese Füllzeichenfolge an die ursprünglichen Daten an.

     return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

Hier ist die Verschlüsselung selbst. Verwenden MCRYPT_RIJNDAEL_128 anstatt MCRYPT_DES.

 }

Jetzt die andere Richtung:

 function decrypt($str, $key)
 {   
     $str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

Die Entschlüsselung. (Sie würden natürlich den Algorithmus wie oben ändern). $str ist jetzt die entschlüsselte Zeichenfolge, einschließlich der Auffüllung.

     $block = mcrypt_get_block_size('des', 'ecb');

Dies ist wieder die Blockgröße. (Siehe oben.)

     $pad = ord($str[($len = strlen($str)) - 1]);

Das sieht etwas seltsam aus. Schreiben Sie es besser in mehreren Schritten:

    $len = strlen($str);
    $pad = ord($str[$len-1]);

$len ist jetzt die Länge der aufgefüllten Zeichenfolge und $str[$len - 1] ist das letzte Zeichen dieser Zeichenfolge. ord wandelt diese in eine Zahl um. Daher $pad ist die Zahl, die wir zuvor als Füllwert für die Polsterung verwendet haben, und dies ist die Polsterungslänge.

     return substr($str, 0, strlen($str) - $pad);

Also schneiden wir jetzt den letzten ab $pad Bytes aus der Zeichenfolge. (Anstatt strlen($str) wir könnten auch schreiben $len Hier: substr($str, 0, $len - $pad).).

 }

?>

Beachten Sie, dass anstatt zu verwenden substr($str, $len - $pad)kann man auch schreiben substr($str, -$pad)als die substr Funktion in PHP hat eine spezielle Handhabung für negative Operanden/Argumente, um vom Ende des Strings zu zählen. (Ich weiß nicht, ob dies mehr oder weniger effizient ist, als zuerst die Länge zu ermitteln und den Index manuell zu berechnen.)

Wie bereits gesagt und im Kommentar von rossum angemerkt, sollte man die Polsterung nicht wie hier einfach abziehen, sondern auf Korrektheit prüfen – also anschauen substr($str, $len - $pad)und überprüfen Sie, ob alle seine Bytes sind chr($pad). Dies dient als leichte Überprüfung gegen Korruption (obwohl diese Überprüfung effektiver ist, wenn Sie einen Verkettungsmodus anstelle von ECB verwenden, und kein Ersatz für einen echten MAC ist).


(Und sagen Sie Ihrem Kunden trotzdem, dass er darüber nachdenken sollte, zu einem sichereren Modus als ECB zu wechseln.)

  • Wenn Sie einen Beispielcode dafür in Pseudocode oder Java geben könnten, wäre das großartig. Ich verstehe immer noch nicht ganz, wie das geht, dh was ist die angegebene Blockgröße, was ist das letzte decodierte Byte usw

    – Ali

    7. September 2011 um 2:34 Uhr

  • Wenn Sie die Polsterung entfernen, sollten Sie sie nicht einfach entfernen. Du solltest prüfen dass es stimmt. Wenn dies der Fall ist, fahren Sie fort, wenn es nicht korrekt ist, löschen Sie den entschlüsselten Text und werfen Sie einen Füllfehler aus.

    – Rossum

    9. September 2011 um 14:17 Uhr

  • WARNUNG: Wenn ein Angreifer online auf falsche Paddings testen kann, kann ein Angreifer erstellen Polsterorakelangriffe das kann die Vertraulichkeit vollständig zerstören. Verwenden Sie einen MAC oder HMAC über IV und Chiffretext, um dieses Szenario zu vermeiden.

    – Maarten Bodewes

    21. Dezember 2014 um 15:02 Uhr

  • In Ihrer Entschlüsselungsfunktion berechnen Sie $block, verwenden es aber nicht in der Funktion. Warum?

    – Omarjebari

    2. August 2016 um 11:27 Uhr

  • @omarjebari Um ehrlich zu sein, habe ich keine Ahnung. Ich habe den Code aus den Kommentaren der Benutzer auf die verlinkte Seite des PHP-Dokuments kopiert und einfach meine Kommentare hinzugefügt. (Der verlinkte Kommentar ist seitdem entweder weg oder die IDs auf der Seite haben sich geändert.)

    – Paulo Ebermann

    2. August 2016 um 18:02 Uhr

Wie kann man PKCS7 Padding aus einer AES verschlusselten Zeichenfolge hinzufugenentfernen
Maarten Bodewes

Ich habe zwei Methoden erstellt, um das Auffüllen und Auffüllen durchzuführen. Die Funktionen werden mit dokumentiert phpdoc und erfordern PHP 5. Wie Sie feststellen werden, enthält die Unpad-Funktion eine Menge Ausnahmebehandlung und generiert nicht weniger als 4 verschiedene Meldungen für jeden möglichen Fehler.

Um die Blockgröße für PHP mcrypt zu ermitteln, können Sie verwenden mcrypt_get_block_sizedie auch die Blockgröße in Bytes anstelle von Bits definiert.

/**
 * Right-pads the data string with 1 to n bytes according to PKCS#7,
 * where n is the block size.
 * The size of the result is x times n, where x is at least 1.
 * 
 * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
 * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
 *
 * @param string $plaintext the plaintext encoded as a string containing bytes
 * @param integer $blocksize the block size of the cipher in bytes
 * @return string the padded plaintext
 */
function pkcs7pad($plaintext, $blocksize)
{
    $padsize = $blocksize - (strlen($plaintext) % $blocksize);
    return $plaintext . str_repeat(chr($padsize), $padsize);
}

/**
 * Validates and unpads the padded plaintext according to PKCS#7.
 * The resulting plaintext will be 1 to n bytes smaller depending on the amount of padding,
 * where n is the block size.
 *
 * The user is required to make sure that plaintext and padding oracles do not apply,
 * for instance by providing integrity and authenticity to the IV and ciphertext using a HMAC.
 *
 * Note that errors during uppadding may occur if the integrity of the ciphertext
 * is not validated or if the key is incorrect. A wrong key, IV or ciphertext may all
 * lead to errors within this method.
 *
 * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
 * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
 *
 * @param string padded the padded plaintext encoded as a string containing bytes
 * @param integer $blocksize the block size of the cipher in bytes
 * @return string the unpadded plaintext
 * @throws Exception if the unpadding failed
 */
function pkcs7unpad($padded, $blocksize)
{
    $l = strlen($padded);

    if ($l % $blocksize != 0) 
    {
        throw new Exception("Padded plaintext cannot be divided by the block size");
    }

    $padsize = ord($padded[$l - 1]);

    if ($padsize === 0)
    {
        throw new Exception("Zero padding found instead of PKCS#7 padding");
    }    

    if ($padsize > $blocksize)
    {
        throw new Exception("Incorrect amount of PKCS#7 padding for blocksize");
    }

    // check the correctness of the padding bytes by counting the occurance
    $padding = substr($padded, -1 * $padsize);
    if (substr_count($padding, chr($padsize)) != $padsize)
    {
        throw new Exception("Invalid PKCS#7 padding encountered");
    }

    return substr($padded, 0, $l - $padsize);
}

Dies macht die Antwort von Paŭlo Ebermann in keiner Weise ungültig, es ist im Grunde dieselbe Antwort in Code & PHPDoc statt als Beschreibung.


Beachten Sie, dass die Rückgabe eines Padding-Fehlers an einen Angreifer zu a führen kann Polsterung Orakelangriff was CBC vollständig unterbricht (wenn CBC anstelle von ECB oder einer sicheren authentifizierten Chiffre verwendet wird).

Rufen Sie einfach die folgende Funktion auf, nachdem Sie die Daten entschlüsselt haben

function removePadding($decryptedText){
    $strPad = ord($decryptedText[strlen($decryptedText)-1]);
    $decryptedText= substr($decryptedText, 0, -$strPad);
    return $decryptedText;
}

  • Der Antwortcode funktioniert nicht mit Nullauffüllung, die von PHP mcrypt standardmäßig verwendet wird. Für PKCS#7/PKCS#5-Padding muss überprüft werden, ob das Padding gültig ist. Erwägen Sie die Verwendung des falschen Schlüssels, $strPad wäre höchstwahrscheinlich falsch, möglicherweise ein Wert, der größer als die Länge der Daten ist. Aber geben Sie keinen schlechten Padding-Fehler zurück, der dazu neigt, ein Padding-Orakel zu erzeugen, sondern tun Sie einfach nichts. Die meisten Bibliotheken unterstützen PKCS#7-Padding und fügen beim Verschlüsseln automatisch Padding hinzu und entfernen das Padding beim Entschlüsseln – es muss nichts weiter getan werden.

    – zaph

    22. Dezember 2017 um 13:41 Uhr

974970cookie-checkWie kann man PKCS7-Padding aus einer AES-verschlüsselten Zeichenfolge hinzufügen/entfernen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy