Wie verschlüsselt und entschlüsselt man einen PHP-String?


225

Was ich meine ist:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

Vielleicht so etwas wie:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • Wie können Sie dies in PHP tun?

Versucht zu verwenden Crypt_Blowfish, aber es hat bei mir nicht funktioniert.


35
@ Rogue Er will keinen Hash, er will symmetrische Verschlüsselung (wie AES), er weiß nur nicht, wie es heißt. (Und jetzt tut er :))
Patashu

Wie sicher muss es sein?

3
@ 夏 期 劇場, Sie "salzen" nicht symmetrische Verschlüsselung, Sie verwenden einen Schlüssel. Ein Schlüssel muss geheim gehalten werden. Ein Salt kann öffentlich sein, ohne die Sicherheit zu beeinträchtigen (solange das Salz eines jeden anders ist), und es ist ein Begriff, der beim Hashing von Passwörtern verwendet wird.
Patashu

2
Sie benötigen ein Salz (privater Schlüssel), einen öffentlichen Schlüssel ein einen Verschlüsselungsalgorithmus wie AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
Wappy

8
@CristianFlorea Der Autor dieses Blogposts verwendet Begriffe, die im Kontext der symmetrischen Verschlüsselung einfach nicht den geringsten Sinn ergeben. Bei AES gibt es weder einen öffentlichen Schlüssel noch ein Salz. Es gibt einen einzigen Schlüssel; es muss geheim gehalten werden. In einigen Betriebsarten gibt es eine IV, die nicht geheim sein muss, aber eine IV ist kein Salz (je nach Modus können ganz unterschiedliche Anforderungen gestellt werden) und muss nicht geheim sein, während der eigentliche Verschlüsselungsschlüssel absolut nicht öffentlich sein kann. Der öffentliche / private Schlüssel gilt für asymmetrische Krypto, hat jedoch nichts mit AES zu tun.
cpast

Antworten:


410

Bevor Sie weitere Schritte ausführen, sollten Sie den Unterschied zwischen Verschlüsselung und Authentifizierung verstehen und wissen , warum Sie wahrscheinlich eine authentifizierte Verschlüsselung und nicht nur eine Verschlüsselung wünschen .

Um eine authentifizierte Verschlüsselung zu implementieren, möchten Sie dann MAC verschlüsseln. Die Reihenfolge der Verschlüsselung und Authentifizierung ist sehr wichtig! Eine der vorhandenen Antworten auf diese Frage machte diesen Fehler; ebenso wie viele in PHP geschriebene Kryptographie-Bibliotheken.

Sie sollten die Implementierung Ihrer eigenen Kryptografie vermeiden und stattdessen eine sichere Bibliothek verwenden, die von Kryptografieexperten geschrieben und überprüft wurde.

Update: PHP 7.2 bietet jetzt libsodium ! Aktualisieren Sie Ihre Systeme für beste Sicherheit auf PHP 7.2 oder höher und befolgen Sie nur die libsodium-Hinweise in dieser Antwort.

Verwenden Sie libsodium, wenn Sie PECL-Zugriff haben (oder natrium_compat, wenn Sie libsodium ohne PECL möchten). sonst ...
Verwenden Sie Defuse / PHP-Verschlüsselung ; Rollen Sie nicht Ihre eigene Kryptographie!

Beide oben verlinkten Bibliotheken machen es einfach und problemlos, authentifizierte Verschlüsselung in Ihren eigenen Bibliotheken zu implementieren.

Wenn Sie dennoch Ihre eigene Kryptografiebibliothek schreiben und bereitstellen möchten, müssen Sie diese Schritte unternehmen, die der herkömmlichen Weisheit jedes Kryptografieexperten im Internet widersprechen.

Verschlüsselung:

  1. Verschlüsseln Sie mit AES im CTR-Modus. Sie können auch GCM verwenden (wodurch die Notwendigkeit eines separaten MAC entfällt). Darüber hinaus sind ChaCha20 und Salsa20 (von libsodium bereitgestellt ) Stream-Chiffren und benötigen keine speziellen Modi.
  2. Sofern Sie oben nicht GCM ausgewählt haben, sollten Sie den Chiffretext mit HMAC-SHA-256 authentifizieren (oder für die Stream-Chiffren mit Poly1305 - die meisten libsodium-APIs tun dies für Sie). Der MAC sollte sowohl die IV als auch den Chiffretext abdecken!

Entschlüsselung:

  1. Wenn Poly1305 oder GCM nicht verwendet wird, berechnen Sie den MAC des Chiffretextes neu und vergleichen Sie ihn mit dem MAC, der mit gesendet wurde hash_equals(). Wenn dies fehlschlägt, brechen Sie den Vorgang ab.
  2. Entschlüsseln Sie die Nachricht.

Weitere Überlegungen zum Design:

  1. Komprimieren Sie niemals etwas. Chiffretext ist nicht komprimierbar; Das Komprimieren von Klartext vor der Verschlüsselung kann zu Informationslecks führen (z. B. CRIME und BREACH auf TLS).
  2. Stellen Sie sicher, dass Sie mb_strlen()und mb_substr()den '8bit'Zeichensatzmodus verwenden, um mbstring.func_overloadProbleme zu vermeiden .
  3. IVs sollten mit einem CSPRNG generiert werden . Wenn Sie verwenden mcrypt_create_iv(), NICHT VERWENDENMCRYPT_RAND !
  4. Wenn Sie kein AEAD-Konstrukt verwenden, verschlüsseln Sie IMMER MAC!
  5. bin2hex(), base64_encode()usw. können Informationen über Ihre Verschlüsselungsschlüssel über das Cache-Timing verlieren. Vermeiden Sie sie wenn möglich.

Selbst wenn Sie den hier gegebenen Ratschlägen folgen, kann bei der Kryptografie viel schief gehen. Lassen Sie Ihre Implementierung immer von einem Kryptografieexperten überprüfen. Wenn Sie nicht das Glück haben, mit einem Kryptografiestudenten an Ihrer örtlichen Universität persönlich befreundet zu sein, können Sie sich jederzeit im Cryptography Stack Exchange- Forum beraten lassen.

Wenn Sie eine professionelle Analyse Ihrer Implementierung benötigen, können Sie jederzeit ein seriöses Team von Sicherheitsberatern beauftragen, um Ihren PHP-Kryptografiecode zu überprüfen (Offenlegung: mein Arbeitgeber).

Wichtig: Wann keine Verschlüsselung verwendet werden soll

Kennwörter nicht verschlüsseln . Sie wollen Hash sie stattdessen eine dieser Passwort-HashingAlgorithmen:

Verwenden Sie niemals eine universelle Hash-Funktion (MD5, SHA256) zur Kennwortspeicherung.

Verschlüsseln Sie keine URL-Parameter . Es ist das falsche Werkzeug für den Job.

Beispiel für die Verschlüsselung von PHP-Zeichenfolgen mit Libsodium

Wenn Sie PHP <7.2 verwenden oder auf andere Weise libsodium nicht installiert haben, können Sie Natrium_Kompat verwenden , um dasselbe Ergebnis zu erzielen (wenn auch langsamer).

<?php
declare(strict_types=1);

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 * @throws RangeException
 */
function safeEncrypt(string $message, string $key): string
{
    if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
        throw new RangeException('Key is not the correct size (must be 32 bytes).');
    }
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    $cipher = base64_encode(
        $nonce.
        sodium_crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
    sodium_memzero($message);
    sodium_memzero($key);
    return $cipher;
}

/**
 * Decrypt a message
 * 
 * @param string $encrypted - message encrypted with safeEncrypt()
 * @param string $key - encryption key
 * @return string
 * @throws Exception
 */
function safeDecrypt(string $encrypted, string $key): string
{   
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

    $plain = sodium_crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
    if (!is_string($plain)) {
        throw new Exception('Invalid MAC');
    }
    sodium_memzero($ciphertext);
    sodium_memzero($key);
    return $plain;
}

Dann um es auszuprobieren:

<?php
// This refers to the previous code block.
require "safeCrypto.php"; 

// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';

$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Halit - Libsodium leichter gemacht

Eines der Projekte, an denen ich gearbeitet habe, ist eine Verschlüsselungsbibliothek namens Halite , die darauf abzielt, libsodium einfacher und intuitiver zu machen.

<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;

// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');

$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Die gesamte zugrunde liegende Kryptographie wird von libsodium verwaltet.

Beispiel mit Defuse / PHP-Verschlüsselung

<?php
/**
 * This requires https://github.com/defuse/php-encryption
 * php composer.phar require defuse/php-encryption
 */

use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

require "vendor/autoload.php";

// Do this once then store it somehow:
$key = Key::createNewRandomKey();

$message = 'We are all living in a yellow submarine';

$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Hinweis : Crypto::encrypt()Gibt eine hexadezimal codierte Ausgabe zurück.

Verwaltung von Verschlüsselungsschlüsseln

Wenn Sie versucht sind, ein "Passwort" zu verwenden, hören Sie sofort auf. Sie benötigen einen zufälligen 128-Bit-Verschlüsselungsschlüssel, kein menschliches, einprägsames Passwort.

Sie können einen Verschlüsselungsschlüssel für die langfristige Verwendung wie folgt speichern:

$storeMe = bin2hex($key);

Und auf Anfrage können Sie es wie folgt abrufen:

$key = hex2bin($storeMe);

Ich empfehle dringend , nur einen zufällig generierten Schlüssel für die langfristige Verwendung anstelle eines Kennworts als Schlüssel zu speichern (oder den Schlüssel abzuleiten).

Wenn Sie die Bibliothek von Defuse verwenden:

"Aber ich möchte wirklich ein Passwort verwenden."

Das ist eine schlechte Idee, aber okay, so geht's sicher.

Generieren Sie zunächst einen zufälligen Schlüssel und speichern Sie ihn in einer Konstanten.

/**
 * Replace this with your own salt! 
 * Use bin2hex() then add \x before every 2 hex characters, like so:
 */
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");

Beachten Sie, dass Sie zusätzliche Arbeit hinzufügen und diese Konstante einfach als Schlüssel verwenden können, um sich viel Herzschmerz zu ersparen!

Verwenden Sie dann PBKDF2 (wie folgt), um einen geeigneten Verschlüsselungsschlüssel aus Ihrem Passwort abzuleiten, anstatt direkt mit Ihrem Passwort zu verschlüsseln.

/**
 * Get an AES key from a static password and a secret salt
 * 
 * @param string $password Your weak password here
 * @param int $keysize Number of bytes in encryption key
 */
function getKeyFromPassword($password, $keysize = 16)
{
    return hash_pbkdf2(
        'sha256',
        $password,
        MY_PBKDF2_SALT,
        100000, // Number of iterations
        $keysize,
        true
    );
}

Verwenden Sie nicht nur ein 16-stelliges Passwort. Ihr Verschlüsselungsschlüssel wird komisch kaputt gehen.


3
Verschlüsseln Sie keine Passwörter , hacken Sie sie mit password_hash()und überprüfen Sie sie mit password_verify().
Scott Arciszewski

2
"Komprimiere niemals etwas." Du meinst wie HTTP, spdy und andere Protokolle? Vor TLS? Absolutistischer Rat viel?
Tiberiu-Ionuț Stan

1
@ScottArciszewski Ich mag Ihren Kommentar zum Schlüssel "// Tun Sie dies einmal und speichern Sie ihn dann irgendwie:" .. irgendwie, lol :)) Nun, wie wäre es, wenn Sie diesen 'Schlüssel' (der ein Objekt ist) als einfache Zeichenfolge speichern, die fest codiert ist? Ich brauche den Schlüssel selbst als String. Kann ich es irgendwie von diesem Objekt bekommen? Vielen Dank
Andrew

2
Thx, ich musste nur eine Zeile ändern, damit Ihre Natriumbeispiele funktionieren:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey Ozerov

1
Beeindruckend! +1 für die Erwähnung, URL-Parameter nicht zu verschlüsseln. Ich mochte die Artikel , den Sie bieten: paragonie.com/blog/2015/09/...
Lynnell Emmanuel Neri

73

Ich bin zu spät zur Party gekommen, aber auf der Suche nach dem richtigen Weg bin ich auf diese Seite gestoßen. Sie war eine der Top-Suchanfragen bei der Google-Suche. Daher möchte ich meine Meinung zu dem Problem mitteilen, das ich für wichtig halte zum Zeitpunkt des Schreibens dieses Beitrags (Anfang 2017) auf dem neuesten Stand. Ab PHP 7.1.0 wird das mcrypt_decryptund mcrypt_encryptveraltet sein, daher sollte beim Erstellen eines zukunftssicheren Codes openssl_encrypt und openssl_decrypt verwendet werden

Sie können so etwas tun wie:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

Wichtig : Dies verwendet den EZB-Modus , der nicht sicher ist. Wenn Sie eine einfache Lösung ohne einen Crashkurs in Kryptografietechnik suchen, schreiben Sie sie nicht selbst, sondern verwenden Sie einfach eine Bibliothek.

Abhängig von Ihren Sicherheitsanforderungen können Sie auch andere Häckslermethoden verwenden. Informationen zu den verfügbaren Chipper-Methoden finden Sie in der Funktion openssl_get_cipher_methods .


10
Vielen Dank, ich bin überrascht, dass diese einfache und klare Antwort nicht mehr positiv bewertet wird. Ich würde lieber keine 10-seitige Diskussion zu diesem Thema lesen, wie die beste Antwort, wenn ich nur eine einfache Zeichenfolge verschlüsseln / entschlüsseln möchte.
Laurent

4
Dies ist keine sichere Antwort. Der EZB-Modus sollte nicht verwendet werden. Wenn Sie eine "einfache und klare Antwort" wünschen, verwenden Sie einfach eine Bibliothek .
Scott Arciszewski

2
@ScottArciszewski, ja, ich gebe zu, ich habe zu schnell gesprochen, als ich nach einem einfachen Code gesucht habe. Ich habe seitdem eine IV hinzugefügt und CBC in meinem eigenen Code verwendet, was für meine Verwendung gut genug ist.
Laurent

Lesen Sie dies und überdenken Sie . Im CBC-Modus kann ein Angreifer die Nachricht vollständig ändern. Wenn es sich bei der Nachricht um eine Datei handelt, kann ein Angreifer Bits umdrehen und calc.exe anzeigen. Das Risiko einer nicht authentifizierten Verschlüsselung ist schwerwiegend.
Scott Arciszewski

7
Es hängt alles vom Anwendungsfall ab! Es gibt Fälle, in denen dies vollkommen in Ordnung ist. Zum Beispiel möchte ich einen GET-Parameter von Seite zu Seite übergeben, sagen wir, prod_id=123aber ich möchte 123 nicht für alle lesbar machen, aber selbst wenn sie ihn lesen könnten, wird es kein Problem sein. Ein Angreifer, der in der Lage ist, die 123 durch einen benutzerdefinierten Wert zu ersetzen, verursacht keinen Schaden. Er kann nur Details zu anderen Produkten abrufen, aber Joe Average User hat keine Ahnung, wie er Details abrufen kann Produkt 124 zum Beispiel. Für ein Szenario wie dieses ist es eine perfekte Lösung, für die Sicherheit ist es ein No Go!
Emil Borconi

43

Was nicht zu tun

WARNUNG:
Diese Antwort verwendet die EZB . Die EZB ist kein Verschlüsselungsmodus, sondern nur ein Baustein. Die Verwendung der EZB, wie in dieser Antwort gezeigt, verschlüsselt die Zeichenfolge nicht wirklich sicher. Verwenden Sie die EZB nicht in Ihrem Code. Siehe Scotts Antwort für eine gute Lösung.

Ich habe es auf mich genommen. Eigentlich habe ich auf Google eine Antwort gefunden und einfach etwas geändert. Das Ergebnis ist jedoch völlig unsicher.

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>

8
Sie können entweder "MCRYPT_MODE_CBC" anstelle von "MCRYPT_MODE_ECB" verwenden, um mehr Sicherheit zu gewährleisten.
Parixit

10
Ramesh, das liegt daran, dass Sie die verschlüsselten Rohdaten erhalten. Sie können eine schönere Version der verschlüsselten Daten erhalten, indem Sie base64 verwenden, wie base64_encode(encrypt($string))decrypt(base64_decode($encrypted))
folgt

82
WARNUNG: Dies ist unsicher . Der EZB-Modus sollte nicht für Zeichenfolgen verwendet werden, die EZB nimmt keine IV an, diese ist nicht authentifiziert, sie verwendet eine alte Chiffre (Blowfish) anstelle von AES, der Schlüssel ist nicht binär usw. usw. Die SO-Community sollte die Upvoting-Verschlüsselung wirklich beenden / Entschlüsselung, die nur "funktioniert" und mit der Abstimmung von Antworten beginnt, von denen bekannt ist, dass sie sicher sind. Wenn Sie das nicht sicher wissen, stimmen Sie nicht ab.
Maarten Bodewes

3
Ich habe dies bereits getan, indem ich den Beispielcode von mcrypt_encryptersetzt habe: php.net/manual/en/function.mcrypt-encrypt.php . Beachten Sie, dass beim Überprüfen jetzt wahrscheinlich ein rtrimfor-Zeichen "\0"am Ende stehen sollte.
Maarten Bodewes

4
Die richtige Antwort ist, etwas wie Entschärfung / PHP-Verschlüsselung zu verwenden, anstatt Ihren eigenen mcrypt-Code zu schreiben.
Scott Arciszewski

18

Für Laravel Framework

Wenn Sie das Laravel-Framework verwenden, ist das Ver- und Entschlüsseln mit internen Funktionen einfacher.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

Hinweis: Stellen Sie sicher, dass Sie in der Schlüsseloption der Datei config / app.php eine zufällige Zeichenfolge mit 16, 24 oder 32 Zeichen festlegen. Andernfalls sind verschlüsselte Werte nicht sicher.


1
Sicher, es kann einfach zu bedienen sein. Aber ist es sicher? Wie werden die Probleme in stackoverflow.com/a/30159120/781723 behoben ? Verwendet es authentifizierte Verschlüsselung? Vermeidet es Schwachstellen im Seitenkanal und gewährleistet zeitgleiche Gleichheitsprüfungen? Verwendet es einen wirklich zufälligen Schlüssel anstelle eines Passworts / einer Passphrase? Verwendet es eine geeignete Betriebsart? Erzeugt es richtig zufällige IVs?
DW

10

Aktualisiert

PHP 7-fähige Version. Es verwendet die Funktion openssl_encrypt aus der PHP OpenSSL Library .

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);

1
Dies ist eine bessere und viel sicherere Version. Danke, es funktioniert auch wie erwartet.

1
Wie erstellen Sie und wo bewahren Sie den Verschlüsselungsschlüssel auf?
user2800464

7

Historischer Hinweis: Dies wurde zum Zeitpunkt von PHP4 geschrieben. Dies ist, was wir jetzt "Legacy-Code" nennen.

Ich habe diese Antwort aus historischen Gründen hinterlassen - aber einige der Methoden sind jetzt veraltet, die DES-Verschlüsselungsmethode wird nicht empfohlen usw.

Ich habe diesen Code aus zwei Gründen nicht aktualisiert: 1) Ich arbeite nicht mehr mit manuellen Verschlüsselungsmethoden in PHP, und 2) dieser Code erfüllt immer noch den Zweck, für den er bestimmt war: das minimale, vereinfachte Konzept zu demonstrieren, wie Verschlüsselung funktionieren kann in PHP.

Wenn Sie eine ähnlich vereinfachte Quelle für "PHP-Verschlüsselung für Dummies" finden, mit der Benutzer mit 10 bis 20 Codezeilen oder weniger beginnen können, lassen Sie es mich in den Kommentaren wissen.

Darüber hinaus genießen Sie bitte diese klassische Episode der minimalistischen PHP4-Verschlüsselungsantwort der frühen Ära.


Idealerweise haben oder können Sie Zugriff auf die mcrypt PHP-Bibliothek erhalten, da diese sicherlich beliebt und für eine Vielzahl von Aufgaben sehr nützlich ist. Hier finden Sie eine Übersicht über die verschiedenen Arten der Verschlüsselung und einige Beispielcodes: Verschlüsselungstechniken in PHP

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

Einige Warnungen:

1) Verwenden Sie niemals eine reversible oder "symmetrische" Verschlüsselung, wenn ein Einweg-Hash ausreicht.

2) Wenn die Daten wirklich sensibel sind, wie Kreditkarten- oder Sozialversicherungsnummern, hören Sie auf; Sie benötigen mehr als jeder einfache Codeabschnitt, sondern eine Kryptobibliothek, die für diesen Zweck entwickelt wurde, und viel Zeit, um die erforderlichen Methoden zu erforschen. Darüber hinaus ist die Software-Krypto wahrscheinlich <10% der Sicherheit sensibler Daten. Es ist, als würde man ein Kernkraftwerk neu verkabeln - akzeptieren Sie, dass die Aufgabe gefährlich und schwierig ist und dass Sie dies nicht wissen, wenn dies der Fall ist. Die finanziellen Sanktionen können immens sein, daher ist es besser, einen Dienst zu nutzen und die Verantwortung an sie zu senden.

3) Jede Art von leicht implementierbarer Verschlüsselung, wie hier aufgeführt, kann leicht wichtige Informationen, die Sie vor neugierigen Blicken schützen möchten, angemessen schützen oder die Exposition bei versehentlichem / absichtlichem Auslaufen begrenzen. Da der Schlüssel jedoch im Klartext auf dem Webserver gespeichert ist, können sie den Entschlüsselungsschlüssel erhalten, wenn sie die Daten abrufen können.

Wie auch immer, viel Spaß :)


9
Eww, DES. Wo ist AES?
Patashu

2
Vielen Dank! Aber einige Probleme. Ich bekomme M�������f=�_=seltsame Zeichen als das verschlüsselte. Kann ich keine einfachen Charaktere bekommen? Wie : 2a2ffa8f13220befbe30819047e23b2c. Kann ich die LÄNGE von $key_value(fest auf 8 ???) und die LÄNGE der Ausgabe nicht ändern $encrypted_text? (Kann es nicht 32 oder 64 lang sein oder was auch immer länger?)
夏 期 劇場

3
@ 夏 期 劇場 Das Ergebnis der Verschlüsselung sind Binärdaten. Wenn Sie möchten, dass es für Menschen lesbar ist, verwenden Sie Base64- oder Hex-Codierung. "Kann ich die Länge des Schlüsselwerts nicht ändern?" Unterschiedliche symmetrische Verschlüsselungsalgorithmen stellen unterschiedliche Anforderungen an den Schlüsselwert. 'und die LÄNGE der Ausgabe ...' Die Länge des verschlüsselten Textes muss mindestens so lang sein wie der Originaltext, sonst gibt es nicht genügend Informationen, um den Originaltext neu zu erstellen. (Dies ist eine Anwendung des Pigeonhole-Prinzips.) Übrigens sollten Sie AES anstelle von DES verwenden. DES ist leicht zerbrechlich und nicht mehr sicher.
Patashu

8
mcrypt_ecb wurde ab PHP 5.5.0 VERRINGERT. Es wird dringend davon abgeraten, sich auf diese Funktion zu verlassen. php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari

1
@BrianDHall Der Grund dafür, dass dies immer noch zu Abstimmungen führt, ist, dass der EZB-Modus nicht sicher ist (verwenden Sie CBC, CTR, GCM oder Poly1305), DES schwach ist (Sie möchten AES, dh) MCRYPT_RIJNDAEL_128und Chiffretexte authentifiziert werden sollten ( hash_hmac(), überprüft werden) mit hash_equals()).
Scott Arciszewski

7

Wenn Sie keine Bibliothek verwenden möchten (was Sie sollten), verwenden Sie Folgendes (PHP 7):

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);

Kann dies ein Ersatz für stackoverflow.com/a/16606352/126833 sein ? Ich habe das erstere verwendet, bis mein Host auf PHP 7.2 aktualisiert hat.
Anjanesh

@anjanesh Sie werden nicht in der Lage sein, alte Daten mit diesem zu entschlüsseln (verschiedene Algorithmen + dieser überprüft auch die Signatur)
Ascon

2
In Ihrem Fall sollte dies wahrscheinlich tun:define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon

Das ist super!
Anjanesh

2

Dies sind kompakte Methoden zum Ver- und Entschlüsseln von Zeichenfolgen mit PHP mithilfe von AES256 CBC :

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

Verwendung:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");

0

Der folgende Code funktioniert in PHP für alle Zeichenfolgen mit Sonderzeichen

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
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.