it-swarm.com.de

Einfachste bidirektionale Verschlüsselung mit PHP

Was ist die einfachste Methode, um die Zwei-Wege-Verschlüsselung gemeinsam durchzuführen PHP installiert?

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. Momentan verwende ich eine RC4-Implementierung, aber wenn ich etwas nativ Unterstütztes finde, kann ich eine Menge unnötigen Code sparen.

206
user1206970

Bearbeitet:

Sie sollten wirklich openssl_encrypt () & openssl_decrypt () verwenden

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

Es gibt sogar einen RFC zum Entfernen von Mcrypt aus PHP - https://wiki.php.net/rfc/mcrypt-viking-funeral

180
472084

Wichtig : Sofern Sie keinenveryspecific use-case haben, verschlüsseln Sie keine Passwörter Verwenden Sie stattdessen einen Passwort-Hashing-Algorithmus. Wenn jemand sagt, dass erencryptseine Passwörter in einer serverseitigen Anwendung verwendet, ist er entweder nicht informiert oder beschreibt ein gefährliches Systemdesign. Passwörter sicher speichern ist ein völlig anderes Problem als die Verschlüsselung.

Informiert werden. Entwerfen Sie sichere Systeme.

Portable Datenverschlüsselung in PHP

Wenn Sie PHP 5.4 oder neuer verwenden und kein Kryptografiemodul selbst schreiben möchten, empfehle ich die Verwendung von einer vorhandenen Bibliothek, die authentifizierte Verschlüsselung bietet Von mir verlinkte Bibliothek stützt sich nur auf das, was PHP liefert und wird regelmäßig von einer Handvoll Sicherheitsforschern überprüft. (Ich selbst eingeschlossen.)

Wenn Ihre Portabilitätsziele nicht verhindern, dass PECL-Erweiterungen erforderlich sind, lautet libsodiumin hohem Maßeempfohlen über alles, was Sie oder ich in PHP schreiben können.

Update (2016-06-12): Sie können jetzt sodium_compat verwenden und dieselben Crypto Libsodium-Angebote verwenden, ohne PECL-Erweiterungen zu installieren.

Wenn Sie sich in der Kryptografie-Technik versuchen möchten, lesen Sie weiter.


Zunächst sollten Sie sich die Zeit nehmen, um sich mit den Gefahren nicht authentifizierter Verschlüsselung und dem Cryptographic Doom-Prinzip vertraut zu machen.

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

Ver- und Entschlüsselung

Die Verschlüsselung in PHP ist eigentlich einfach (wir werden openssl_encrypt() und openssl_decrypt() verwenden, sobald Sie welche vorgenommen haben Entscheidungen über die Verschlüsselung Ihrer Daten. Konsultieren Sie 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 ein wichtiges Problem darstellt (größer ist wahrscheinlichnichtbesser, da die Schlüsselplanung nicht stimmt) im 256-Bit-Modus).

Hinweis: Wir verwenden mcrypt nicht, da es sich um Abandonware handelt und nicht gepatchte Bugs die möglicherweise aus Sicherheitsgründen vorliegen -beeinflussend. Aus diesen Gründen ermutige ich andere PHP Entwickler, dies ebenfalls zu vermeiden.

Simple Encryption/Decryption 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 oben genannte einfache Kryptobibliothek ist immer noch nicht sicher zu verwenden. Wir müssen Chiffretexte authentifizieren und überprüfen, bevor wir entschlüsseln.

Hinweis : Standardmäßig gibt UnsafeCrypto::encrypt() eine rohe Binärzeichenfolge zurück. Nennen Sie es wie folgt, 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

Simple Authentication Wrapper

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 : raw binary , base64-codiert


Wenn jemand diese SaferCrypto - Bibliothek in einer Produktionsumgebung oder Ihre eigene Implementierung derselben Konzepte verwenden möchte, empfehle ich dringend, sich vor Ihnen an Ihre ansässigen Kryptographen zu wenden, um eine zweite Meinung einzuholen. Sie können Ihnen über Fehler berichten, die mir vielleicht gar nicht bewusst sind.

Sie werden viel besser dran sein, wenn Sie eine seriöse Kryptografiebibliothek verwenden.

207

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

[~ # ~] edit [~ # ~]

5 Jahre und 4 Monate nach dieser Antwort wird die Erweiterung mcrypt derzeit aus PHP entfernt.

22
Eugen Rieck

PHP 7.2 wurde komplett von Mcrypt entfernt und die Verschlüsselung basiert nun auf der wartbaren Libsodium Bibliothek.

Alle Ihre Verschlüsselungsanforderungen können im Grunde durch die Bibliothek Libsodium gelöst werden.

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

4
Hemerson Varela

Hier ist eine einfache, aber ausreichend sichere Implementierung:

  • AES-256-Verschlüsselung im CBC-Modus
  • PBKDF2 zum Erstellen eines Verschlüsselungsschlüssels aus einem Klartextkennwort
  • HMAC zur Authentifizierung der verschlüsselten Nachricht.

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

2
Eugene Fidelin