Einfachste Zwei-Wege-Verschlüsselung mit PHP

Lesezeit: 13 Minuten

Einfachste Zwei Wege Verschlusselung mit PHP
Benutzer1206970

Was ist der einfachste Weg, um eine Zwei-Wege-Verschlüsselung in gängigen PHP-Installationen durchzuführen?

Ich muss in der Lage sein, Daten mit einem Zeichenfolgenschlüssel zu verschlüsseln und denselben Schlüssel zum Entschlüsseln am anderen Ende zu verwenden.

Die Sicherheit ist nicht so wichtig wie die Portabilität des Codes, daher möchte ich die Dinge so einfach wie möglich halten. Derzeit verwende ich eine RC4-Implementierung, aber wenn ich etwas finde, das nativ unterstützt wird, kann ich mir eine Menge unnötigen Code sparen.

  • XOR einfach deine Zeichenfolge.

    – Thunraz

    13. Februar 2012 um 14:28 Uhr

  • Verwenden Sie für allgemeine Verschlüsselungen entschärfen/php-verschlüsselung/ anstatt selbst zu rollen.

    – Scott Arciszewski

    11. Mai 2015 um 4:37 Uhr

  • Hände weg von github.com/defuse/php-verschlüsselung – Es ist um Größenordnungen langsamer als mcrypt.

    – Eugen Rieck

    11. Mai 2015 um 16:12 Uhr

  • @Scott Das Denken nach dem Motto “Das wird wahrscheinlich nicht der Engpass sein” hat uns eine Menge schlechter Software gebracht.

    – Eugen Rieck

    12. Mai 2015 um 14:30 Uhr

  • Wenn Sie wirklich viele Daten bis zu dem Punkt verschlüsseln/entschlüsseln, dass die Millisekunden, die es kostet, Ihre Anwendung verstopfen, beißen Sie in den sauren Apfel und wechseln Sie zu libsodium. Sodium::crypto_secretbox() und Sodium::crypto_secretbox_open() sind sicher und performant.

    – Scott Arciszewski

    12. Mai 2015 um 18:53 Uhr

1646879051 233 Einfachste Zwei Wege Verschlusselung mit PHP
Scott Arciszewski

Wichtig: Es sei denn, Sie haben eine sehr besonderer Anwendungsfall, Passwörter nicht verschlüsseln, verwenden Sie stattdessen einen Passwort-Hashing-Algorithmus. Wenn jemand sie sagt Verschlüsseln ihre Passwörter in einer serverseitigen Anwendung, sind sie entweder nicht informiert oder beschreiben ein gefährliches Systemdesign. Passwörter sicher speichern ist ein völlig anderes Problem als die Verschlüsselung.

Informiert werden. Entwerfen Sie sichere Systeme.

Verschlüsselung portabler Daten in PHP

Wenn Sie verwenden PHP 5.4 oder neuer und kein Kryptografiemodul selbst schreiben möchten, empfehle ich die Verwendung von eine vorhandene Bibliothek, die eine authentifizierte Verschlüsselung bereitstellt. Die Bibliothek, die ich verlinkt habe, stützt sich nur auf das, was PHP bietet, und wird regelmäßig von einer Handvoll Sicherheitsforschern überprüft. (Mich eingenommen.)

Wenn Ihre Portabilitätsziele nicht verhindern, dass PECL-Erweiterungen erforderlich sind, libnatrium ist höchst empfohlen über alles, was Sie oder ich in PHP schreiben können.

Aktualisierung (2016-06-12): Sie können jetzt verwenden Natrium_kompat und nutzen Sie die gleichen Krypto-Libsodium-Angebote, ohne PECL-Erweiterungen zu installieren.

Wenn Sie sich in der Kryptografietechnik versuchen möchten, lesen Sie weiter.


Zunächst sollten Sie sich Zeit nehmen, um zu lernen die Gefahren einer nicht authentifizierten Verschlüsselung und das kryptografische Doom-Prinzip.

  • Verschlüsselte Daten können immer noch von einem böswilligen Benutzer manipuliert werden.
  • Die Authentifizierung der verschlüsselten Daten verhindert Manipulationen.
  • Die Authentifizierung der unverschlüsselten Daten verhindert keine Manipulation.

Verschlüsselung und Entschlüsselung

Die Verschlüsselung in PHP ist eigentlich einfach (wir werden verwenden openssl_encrypt() und openssl_decrypt() sobald Sie einige Entscheidungen darüber getroffen haben, wie Sie Ihre Informationen verschlüsseln. Konsultieren openssl_get_cipher_methods() für eine Liste der auf Ihrem System unterstützten Methoden. Die beste Wahl ist AES im CTR-Modus:

  • aes-128-ctr
  • aes-192-ctr
  • aes-256-ctr

Es gibt derzeit keinen Grund zu der Annahme, dass die AES-Schlüsselgröße ist ein wichtiges Problem, über das man sich Sorgen machen muss (größer ist wahrscheinlich nicht besser, wegen schlechter Schlüsselplanung im 256-Bit-Modus).

Notiz: Wir verwenden nicht mcrypt denn es ist Abbruchware und hat Ungepatchte Fehler das könnte sicherheitsrelevant sein. Aus diesen Gründen ermutige ich andere PHP-Entwickler, es ebenfalls zu vermeiden.

Einfacher Verschlüsselungs-/Entschlüsselungs-Wrapper mit OpenSSL

class UnsafeCrypto
{
    const METHOD = 'aes-256-ctr';

    /**
     * Encrypts (but does not authenticate) a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded 
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = openssl_random_pseudo_bytes($nonceSize);

        $ciphertext = openssl_encrypt(
            $message,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );

        // Now let's pack the IV and the ciphertext together
        // Naively, we can just concatenate
        if ($encode) {
            return base64_encode($nonce.$ciphertext);
        }
        return $nonce.$ciphertext;
    }

    /**
     * Decrypts (but does not verify) a message
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = mb_substr($message, 0, $nonceSize, '8bit');
        $ciphertext = mb_substr($message, $nonceSize, null, '8bit');

        $plaintext = openssl_decrypt(
            $ciphertext,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );

        return $plaintext;
    }
}

Anwendungsbeispiel

$message="Ready your ammunition; we attack at dawn.";
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

Demo: https://3v4l.org/jl7qR


Die obige einfache Kryptobibliothek ist immer noch nicht sicher zu verwenden. Wir müssen Chiffretexte authentifizieren und verifizieren, bevor wir sie entschlüsseln.

Notiz: Standardmäßig, UnsafeCrypto::encrypt() gibt einen rohen binären String zurück. Nennen Sie es so, wenn Sie es in einem binärsicheren Format (Base64-codiert) speichern müssen:

$message="Ready your ammunition; we attack at dawn.";
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key, true);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key, true);

var_dump($encrypted, $decrypted);

Demo: http://3v4l.org/f5K93

Einfacher Authentifizierungswrapper

class SaferCrypto extends UnsafeCrypto
{
    const HASH_ALGO = 'sha256';

    /**
     * Encrypts then MACs a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded string
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);

        // Pass to UnsafeCrypto::encrypt
        $ciphertext = parent::encrypt($message, $encKey);

        // Calculate a MAC of the IV and ciphertext
        $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);

        if ($encode) {
            return base64_encode($mac.$ciphertext);
        }
        // Prepend MAC to the ciphertext and return to caller
        return $mac.$ciphertext;
    }

    /**
     * Decrypts a message (after verifying integrity)
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string (raw binary)
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        // Hash Size -- in case HASH_ALGO is changed
        $hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
        $mac = mb_substr($message, 0, $hs, '8bit');

        $ciphertext = mb_substr($message, $hs, null, '8bit');

        $calculated = hash_hmac(
            self::HASH_ALGO,
            $ciphertext,
            $authKey,
            true
        );

        if (!self::hashEquals($mac, $calculated)) {
            throw new Exception('Encryption failure');
        }

        // Pass to UnsafeCrypto::decrypt
        $plaintext = parent::decrypt($ciphertext, $encKey);

        return $plaintext;
    }

    /**
     * Splits a key into two separate keys; one for encryption
     * and the other for authenticaiton
     * 
     * @param string $masterKey (raw binary)
     * @return array (two raw binary strings)
     */
    protected static function splitKeys($masterKey)
    {
        // You really want to implement HKDF here instead!
        return [
            hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
            hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
        ];
    }

    /**
     * Compare two strings without leaking timing information
     * 
     * @param string $a
     * @param string $b
     * @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
     * @return boolean
     */
    protected static function hashEquals($a, $b)
    {
        if (function_exists('hash_equals')) {
            return hash_equals($a, $b);
        }
        $nonce = openssl_random_pseudo_bytes(32);
        return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
    }
}

Anwendungsbeispiel

$message="Ready your ammunition; we attack at dawn.";
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = SaferCrypto::encrypt($message, $key);
$decrypted = SaferCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

Demos: rohe Binärdatei, Base64-kodiert


Falls das jemand nutzen möchte SaferCrypto Bibliothek in einer Produktionsumgebung oder Ihre eigene Implementierung der gleichen Konzepte, empfehle ich dringend, sich an zu wenden Ihre ansässigen Kryptografen Holen Sie sich vorher eine zweite Meinung ein. Sie können Ihnen Fehler aufzeigen, die mir vielleicht gar nicht bewusst sind.

Sie werden viel besser dran sein, wenn Sie es verwenden eine seriöse Kryptografie-Bibliothek.

  • Also versuche ich nur, die UnsafeCrypto zuerst zum Laufen zu bringen. Die Verschlüsselung funktioniert einwandfrei, aber jedes Mal, wenn ich die Entschlüsselung ausführe, erhalte ich als Antwort „falsch“. Ich verwende denselben Schlüssel zum Entschlüsseln und gebe sowohl die Codierung als auch die Decodierung wahr. Ich nehme an, dass es sich bei dem Beispiel um einen Tippfehler handelt. Ich frage mich, ob mein Problem daher kommt. Können Sie erklären, woher die Variable $mac kommt, und sollte es einfach $iv sein?

    – David C

    6. Juli 2015 um 21:33 Uhr


  • @EugenRieck Die OpenSSL-Verschlüsselungsimplementierungen sind wahrscheinlich die einzigen Teile, die nicht saugen, und es ist die einzige Möglichkeit, AES-NI in Vanilla PHP zu nutzen. Wenn Sie auf OpenBSD installieren, wird PHP gegen LibreSSL kompiliert, ohne dass der PHP-Code einen Unterschied bemerkt. Libsodium > OpenSSL jeden Tag. Ebenfalls, Verwenden Sie nicht libmcrypt. Was würden Sie PHP-Entwicklern empfehlen, anstelle von OpenSSL zu verwenden?

    – Scott Arciszewski

    22. Juli 2015 um 15:43 Uhr


  • Weder 5.2 noch 5.3 werden mehr unterstützt. Sie sollten sich stattdessen mit der Aktualisierung auf a befassen unterstützte Version von PHPso ein 5.6.

    – Scott Arciszewski

    6. September 2015 um 20:19 Uhr

  • @BBeta paragonie.com/blog/2015/09/…

    – Scott Arciszewski

    6. April 2017 um 18:45 Uhr

  • Ich tat es nur als Demonstration von Sie möchten binäre Zeichenfolgen, keine für Menschen lesbaren Zeichenfolgen, für Ihre Schlüssel.

    – Scott Arciszewski

    26. August 2017 um 16:10 Uhr

Einfachste Zwei Wege Verschlusselung mit PHP
472084

Bearbeitet:

Sie sollten wirklich verwenden openssl_encrypt() & openssl_decrypt()

Wie Scott sagt, ist Mcrypt keine gute Idee, da es seit 2007 nicht mehr aktualisiert wurde.

Es gibt sogar einen RFC, um Mcrypt aus PHP zu entfernen – https://wiki.php.net/rfc/mcrypt-viking-funeral

  • @EugenRieck Ja, das ist der Punkt. Mcrypt erhält keine Patches. OpenSSL erhält Patches, sobald eine große oder kleine Schwachstelle entdeckt wird.

    – Greg

    7. September 2016 um 8:49 Uhr

  • Es wäre besser, für eine so hoch bewertete Antwort auch einfachste Beispiele als Antwort zu geben. trotzdem danke.

    – T. Todua

    18. Januar 2018 um 17:33 Uhr

  • Leute, nur zur Info => MCRYPT IST VERALTET. Capsing, also sollte jeder wissen, dass er es nicht verwenden soll, da es uns eine Vielzahl von Problemen bereitet hat. Es ist seit PHP 7.1 veraltet, wenn ich mich nicht irre.

    – ClusterBuddy

    3. Juni 2019 um 10:29 Uhr

  • Seit PHP 7 wurde die mcrypt-Funktion aus der PHP-Codebasis entfernt. Wenn Sie also die neueste Version von PHP verwenden (was Standard sein sollte), können Sie diese veraltete Funktion nicht mehr verwenden.

    – Alexander Behling

    12. September 2019 um 13:09 Uhr

  • Sie sollten auch erwähnen, dass Mcrypt seit PHP 7.1.0 abgeschrieben und ab PHP 7.2.0 entfernt wurde.

    – Jonathan J. Pecany

    9. September 2020 um 3:06 Uhr

1646879052 857 Einfachste Zwei Wege Verschlusselung mit PHP
Eugen Rieck

Verwenden mcrypt_encrypt() und mcrypt_decrypt() mit entsprechenden Parametern. Wirklich einfach und unkompliziert, und Sie verwenden ein kampferprobtes Verschlüsselungspaket.

BEARBEITEN

5 Jahre und 4 Monate nach dieser Antwort, die mcrypt Die Erweiterung wird derzeit eingestellt und schließlich aus PHP entfernt.

  • Kampferprobt und seit mehr als 8 Jahren nicht mehr aktualisiert?

    – Maarten Bodewes

    9. Oktober 2014 um 9:57 Uhr


  • Nun, mcrypt ist in PHP7 und nicht veraltet – das ist gut genug für mich. Nicht der gesamte Code hat die schreckliche Qualität von OpenSSL und muss alle paar Tage gepatcht werden.

    – Eugen Rieck

    11. Mai 2016 um 4:30 Uhr

  • mcrypt ist nicht nur in Sachen Support miserabel. Es implementiert auch keine Best Practices wie PKCS#7-konformes Padding, authentifizierte Verschlüsselung. Es wird SHA-3 oder andere neue Algorithmen nicht unterstützen, da es von niemandem gewartet wird, was Ihnen einen Upgrade-Pfad raubt. Außerdem akzeptierte es früher Dinge wie Teilschlüssel, das Auffüllen mit Nullen usw. Es gibt einen guten Grund, warum es gerade dabei ist, schrittweise aus PHP entfernt zu werden.

    – Maarten Bodewes

    12. Mai 2016 um 15:09 Uhr

  • In PHP 7.1 lösen alle mcrypt_*-Funktionen eine E_DEPRECATED-Benachrichtigung aus. In PHP 7.1+1 (sei es 7.2 oder 8.0) wird die mcrypt-Erweiterung aus dem Kern heraus und in PECL verschoben, wo Leute, die Ja wirklich installieren möchten, können dies noch tun, wenn sie PHP-Erweiterungen von PECL installieren können.

    – Mladen Janjetović

    20. Mai 2016 um 11:59 Uhr

1646879052 67 Einfachste Zwei Wege Verschlusselung mit PHP
Lonar

Verschlüsseln mit openssl_encrypt() Die Funktion openssl_encrypt bietet eine sichere und einfache Möglichkeit, Ihre Daten zu verschlüsseln.

Im folgenden Skript verwenden wir die AES128-Verschlüsselungsmethode, aber Sie können je nachdem, was Sie verschlüsseln möchten, eine andere Art von Verschlüsselungsmethode in Betracht ziehen.

<?php
$message_to_encrypt = "Yoroshikune";
$secret_key = "my-secret-key";
$method = "aes128";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);

$encrypted_message = openssl_encrypt($message_to_encrypt, $method, $secret_key, 0, $iv);

echo $encrypted_message;
?>

Hier ist eine Erklärung der verwendeten Variablen:

message_to_encrypt : die Daten, die Sie verschlüsseln möchten secret_key : Dies ist Ihr „Passwort“ für die Verschlüsselung. Achten Sie darauf, nichts zu Einfaches zu wählen und achten Sie darauf, Ihren geheimen Schlüssel nicht mit anderen Personen zu teilen. Methode: die Verschlüsselungsmethode. Hier haben wir uns für AES128 entschieden. iv_length und iv : Bereiten Sie die Verschlüsselung mit Bytes vor verschlüsselte_Nachricht : die Variable, die Ihre verschlüsselte Nachricht enthält

Entschlüsseln mit openssl_decrypt() Nachdem Sie Ihre Daten verschlüsselt haben, müssen Sie sie möglicherweise entschlüsseln, um die Nachricht wiederzuverwenden, die Sie zuerst in eine Variable eingefügt haben. Dazu verwenden wir die Funktion openssl_decrypt().

<?php
$message_to_encrypt = "Yoroshikune";
$secret_key = "my-secret-key";
$method = "aes128";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);
$encrypted_message = openssl_encrypt($message_to_encrypt, $method, $secret_key, 0, $iv);

$decrypted_message = openssl_decrypt($encrypted_message, $method, $secret_key, 0, $iv);

echo $decrypted_message;
?>

Die von openssl_decrypt() vorgeschlagene Entschlüsselungsmethode ist in der Nähe von openssl_encrypt().

Der einzige Unterschied besteht darin, dass Sie anstelle von $message_to_encrypt Ihre bereits verschlüsselte Nachricht als erstes Argument von openssl_decrypt() hinzufügen müssen.

Hinweis: Der geheime Schlüssel und iv müssen zum Entschlüsseln gespeichert werden.

PHP7.2 komplett weggezogen Mcrypt und die Verschlüsselung basiert nun auf dem Wartbaren Libsodium Bücherei.

Alle Ihre Verschlüsselungsanforderungen können grundsätzlich durch gelöst werden Libsodium Bücherei.

// On Alice's computer:
$msg = 'This comes from Alice.';
$signed_msg = sodium_crypto_sign($msg, $secret_sign_key);


// On Bob's computer:
$original_msg = sodium_crypto_sign_open($signed_msg, $alice_sign_publickey);
if ($original_msg === false) {
    throw new Exception('Invalid signature');
} else {
    echo $original_msg; // Displays "This comes from Alice."
}

Libsodium-Dokumentation: https://github.com/paragonie/pecl-libsodium-doc

  • Die crypto_sign API tut es nicht Nachrichten verschlüsseln – das erfordert eine der crypto_aead_*_encrypt Funktionen.

    – Roger Dueck

    17. Juli 2019 um 18:07 Uhr

WICHTIG Diese Antwort gilt nur für PHP 5, verwenden Sie in PHP 7 integrierte kryptografische Funktionen.

Hier ist eine einfache, aber sichere Implementierung:

  • AES-256-Verschlüsselung im CBC-Modus
  • PBKDF2 zum Erstellen eines Verschlüsselungsschlüssels aus einem Klartextpasswort
  • HMAC, um die verschlüsselte Nachricht zu authentifizieren.

Code und Beispiele finden Sie hier: https://stackoverflow.com/a/19445173/1387163

  • Die crypto_sign API tut es nicht Nachrichten verschlüsseln – das erfordert eine der crypto_aead_*_encrypt Funktionen.

    – Roger Dueck

    17. Juli 2019 um 18:07 Uhr

985670cookie-checkEinfachste Zwei-Wege-Verschlüsselung mit PHP

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

Privacy policy