
🔒 Dateien in PHP ver- und entschlüsseln: OpenSSL und Sodium statt mcrypt
Verschlüsseln Sie eine Datei, bevor Sie sie auf dem Server speichern, und seien Sie sicher, dass niemand, nicht einmal der Hosting-Administrator, sie ohne den Schlüssel lesen kann. Klingt nach einem grundlegenden Bedürfnis, aber mit dem Wegfall von mcrypt aus PHP funktionierte der vertraute Ansatz nicht mehr.
Die mcrypt-Erweiterung wurde bereits 2017 in PHP 7.1 als veraltet markiert und in PHP 7.2 vollständig entfernt. Heute, unter PHP 8, endet der Versuch, mcrypt_encrypt() aufzurufen, in einem fatalen Fehler. In der Zwischenzeit liegen vertrauliche Dateien weiterhin auf Servern: Datenbank-Backups, CSVs mit personenbezogenen Daten, PDF-Verträge, Bestellexporte.
Die gute Nachricht: PHP bietet zwei funktionierende Mechanismen von Haus aus, OpenSSL und Sodium. Beide erfordern keine zusätzliche Erweiterungsinstallation auf modernen Hosting-Umgebungen, beide sind schneller und sicherer als mcrypt. Nachfolgend finden Sie eine praxisnahe Anleitung zur Ver- und Entschlüsselung von Dateien unter PHP 8 mit Code, den Sie kopieren und ausführen können.
💡 Kurzübersicht:
- Warum mcrypt tot ist und welche PHP-Versionen betroffen sind
- Schritt-für-Schritt-Dateiverschlüsselung via OpenSSL mit AES-256-CBC
- Entschlüsselung mit Manipulationsschutz durch HMAC
- Sodium-Alternative für PHP 7.2 und höher
- Wann OpenSSL und wann Sodium wählen
Warum mcrypt keine Option mehr ist
Die mcrypt-Bibliothek wurde seit 2007 nicht mehr aktualisiert. Im Code wurden kritische Schwachstellen gefunden, und es gab keine Maintainer mehr. Das PHP-Team traf eine Entscheidung: In PHP 7.1 wurde die Erweiterung als veraltet markiert und in PHP 7.2, veröffentlicht im November 2017, vollständig aus dem Kern entfernt.
Wenn Sie ein altes Projekt mit mcrypt migrieren, prüfen Sie phpinfo(). Unter PHP 7.2+ gibt es keine Zeile „mcrypt support: enabled". Der Aufruf von mcrypt_encrypt(), mcrypt_decrypt() oder der Stream-Filter mcrypt.tripledes / mdecrypt.tripledes führt zum Fehler „Call to undefined function".
Technisch ist mcrypt via PECL mit dem Befehl pecl install mcrypt verfügbar. Aber eine nicht unterstützte Erweiterung mit bekannten Schwachstellen auf einem Produktionsserver für ein veraltetes Skript zu installieren, ist keine gute Idee. Schreiben Sie die Verschlüsselung mit OpenSSL neu: Es ist seit Version 5.3 in PHP integriert und wird bleiben.
Dateiverschlüsselung via OpenSSL, Schritt für Schritt
OpenSSL wird in PHP durch die Funktionen openssl_encrypt() und openssl_decrypt() repräsentiert. Sie arbeiten mit Rohdaten und unterstützen Dutzende Algorithmen, von AES-128-CBC bis AES-256-GCM. Für Dateien verwenden wir AES-256-CBC: Es ist kryptografisch stark und benötigt im Gegensatz zu GCM mit zusätzlichen Tag-Parametern kein PHP 7.1.
Schritt 1: Verschlüsselungsschlüssel generieren
Der Schlüssel ist das Hauptgeheimnis des gesamten Schemas. Er muss kryptografisch zufällig sein, nicht manuell ausgedacht. Kein „secret-password" aus Beispielen, nur openssl_random_pseudo_bytes().
Das folgende Skript generiert einen 256-Bit-Schlüssel und gibt ihn in einem Format zur Einfügung in wp-config.php aus. Einmalig via Kommandozeile ausführen und das Ergebnis speichern:
1 <?php 2 // Generating a random 256-bit key (32 bytes) 3 $encryption_key = base64_encode(openssl_random_pseudo_bytes(32)); 4 echo "define('FILE_ENCRYPTION_KEY', '" . $encryption_key . "');\n";
Die Funktion openssl_random_pseudo_bytes(32) gibt 32 Bytes kryptografisch hochwertiger Zufallsdaten zurück. base64_encode konvertiert die Binärdaten in eine Zeichenkette, die sich bequem in Konfigurationsdateien speichern lässt. Der Schlüssel muss außerhalb des Document Root liegen, in wp-config.php oder .env, aber nicht im Theme-Code.
Schritt 2: Funktion zur Dateiverschlüsselung
Das Skript liest eine Datei von der Festplatte, verschlüsselt sie mit dem AES-256-CBC-Algorithmus, stellt einen zufälligen IV voran und eine HMAC-Signatur zur Integritätsprüfung, speichert das Ergebnis. Fügen Sie den Code in die functions.php eines Child-Themes oder in ein eigenes Plugin ein.
Warnung: Erstellen Sie vor der Ausführung auf einem Produktionsserver ein vollständiges Backup. Testen Sie die Ver- und Entschlüsselung an einer Dateikopie in einem Testverzeichnis. Geht der Schlüssel verloren, ist eine Entschlüsselung der Daten unmöglich, AES-256 lässt sich nicht per Brute-Force knacken.
1 <?php 2 function encrypt_file(string $sourcePath, string $destPath, string $key): bool 3 { 4 if (!file_exists($sourcePath)) { 5 throw new RuntimeException('Source file not found: ' . $sourcePath); 6 } 7 8 $plaintext = file_get_contents($sourcePath); 9 if ($plaintext === false) { 10 throw new RuntimeException('Failed to read file'); 11 } 12 13 $cipher = 'aes-256-cbc'; 14 $ivLength = openssl_cipher_iv_length($cipher); 15 $iv = openssl_random_pseudo_bytes($ivLength); 16 17 $ciphertext = openssl_encrypt( 18 $plaintext, 19 $cipher, 20 base64_decode($key), 21 OPENSSL_RAW_DATA, 22 $iv 23 ); 24 25 if ($ciphertext === false) { 26 throw new RuntimeException('Encryption error'); 27 } 28 29 // HMAC signature for integrity verification during decryption 30 $hmac = hash_hmac('sha256', $iv . $ciphertext, base64_decode($key), true); 31 32 // File format: IV (16 bytes) + HMAC (32 bytes) + ciphertext 33 $result = file_put_contents($destPath, $iv . $hmac . $ciphertext); 34 35 return $result !== false; 36 }
Was hier Zeile für Zeile passiert:
openssl_cipher_iv_length('aes-256-cbc')gibt 16 zurück, die Länge des Initialisierungsvektors für diesen Algorithmus.openssl_random_pseudo_bytes($ivLength)erzeugt einen zufälligen IV. Er sorgt dafür, dass identische Daten, mit demselben Schlüssel verschlüsselt, bei jedem Durchlauf einen anderen Geheimtext ergeben.OPENSSL_RAW_DATAweist die Funktion an, Binärdaten zurückzugeben, nicht base64. Wir speichern den rohen Geheimtext aus Gründen der Kompaktheit.hash_hmac('sha256', ...)berechnet eine Prüfsumme über das Bündel aus IV und Geheimtext. Bei der Entschlüsselung wird der HMAC neu berechnet und verglichen: Wurden die Daten verändert oder beschädigt, stimmt der Vergleich nicht überein.- Die Datei wird im Format gespeichert:
[IV 16 bytes][HMAC 32 bytes][ciphertext]. Keine Trennzeichen, die Positionen sind durch die Längen festgelegt.
Schritt 3: Entschlüsselungsfunktion
Der umgekehrte Prozess: IV lesen, HMAC lesen, Geheimtext lesen, HMAC neu berechnen und via hash_equals() vergleichen, entschlüsseln. Der Code wird in dieselbe Datei eingefügt:
1 <?php 2 function decrypt_file(string $sourcePath, string $key): string|false 3 { 4 if (!file_exists($sourcePath)) { 5 throw new RuntimeException('Encrypted file not found: ' . $sourcePath); 6 } 7 8 $data = file_get_contents($sourcePath); 9 if ($data === false) { 10 throw new RuntimeException('Failed to read file'); 11 } 12 13 $cipher = 'aes-256-cbc'; 14 $ivLength = openssl_cipher_iv_length($cipher); 15 $hmacLength = 32; // sha256 = 32 bytes 16 17 $iv = substr($data, 0, $ivLength); 18 $hmac = substr($data, $ivLength, $hmacLength); 19 $ciphertext = substr($data, $ivLength + $hmacLength); 20 21 // Integrity check: recompute HMAC and compare 22 $calculatedHmac = hash_hmac( 23 'sha256', 24 $iv . $ciphertext, 25 base64_decode($key), 26 true 27 ); 28 29 if (!hash_equals($hmac, $calculatedHmac)) { 30 throw new RuntimeException('File corrupted or key invalid'); 31 } 32 33 $plaintext = openssl_decrypt( 34 $ciphertext, 35 $cipher, 36 base64_decode($key), 37 OPENSSL_RAW_DATA, 38 $iv 39 ); 40 41 return $plaintext; 42 }
Entscheidender Punkt: hash_equals() statt ===. Der reguläre Zeichenkettenvergleich ist anfällig für Timing-Angriffe, ein Angreifer kann den HMAC Byte für Byte erraten, indem er die Antwortzeit des Servers misst. hash_equals() vergleicht Zeichenketten in konstanter Zeit, unabhängig davon, an welchem Zeichen sie auseinanderlaufen.
Anwendungsbeispiel mit echten Pfaden
1 <?php 2 $key = FILE_ENCRYPTION_KEY; // from wp-config.php 3 4 // Encrypting the database backup 5 encrypt_file( 6 __DIR__ . '/backup.sql', 7 __DIR__ . '/backup.sql.enc', 8 $key 9 ); 10 11 // Decrypting and serving for download 12 $decrypted = decrypt_file(__DIR__ . '/backup.sql.enc', $key); 13 header('Content-Type: application/octet-stream'); 14 header('Content-Disposition: attachment; filename="backup.sql"'); 15 echo $decrypted;
Die Funktionen sind universell: Sie funktionieren mit jedem Dateityp, Bildern, PDF, CSV, SQL-Dumps. Die Größe ist nur durch den verfügbaren Arbeitsspeicher begrenzt, da die Datei vollständig in den Speicher gelesen wird. Für gigabytegroße Dateien ist eine Streaming-Verarbeitung mit Chunk-Pufferung nötig, aber für die überwiegende Mehrheit der praktischen Aufgaben ist dieser Code ausreichend.
Alternative: Sodium (libsodium)
Die Sodium-Erweiterung ist ab Version 7.2 in PHP integriert und wurde mit PHP 8.1 Teil des Kerns. Sie bietet eine einfachere API im Vergleich zu OpenSSL: Keine Notwendigkeit, IV und HMAC manuell zu verwalten, die authentifizierte Verschlüsselung funktioniert von Haus aus.
1 <?php 2 function sodium_encrypt_file(string $sourcePath, string $destPath, string $key): bool 3 { 4 $plaintext = file_get_contents($sourcePath); 5 $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 6 $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, base64_decode($key)); 7 return file_put_contents($destPath, $nonce . $ciphertext) !== false; 8 } 9 10 function sodium_decrypt_file(string $sourcePath, string $key): string|false 11 { 12 $data = file_get_contents($sourcePath); 13 $nonce = substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 14 $ciphertext = substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 15 $result = sodium_crypto_secretbox_open($ciphertext, $nonce, base64_decode($key)); 16 return $result !== false ? $result : false; 17 }
Hinweis: Sodium prüft die Integrität selbst. Wurden die Daten verändert oder ist der Schlüssel falsch, gibt sodium_crypto_secretbox_open() einfach false zurück, es sind keine separaten HMAC-Prüfungen erforderlich. Der Code ist halb so lang.
Ein Nachteil: Sodium erfordert PHP 7.2 oder höher. Läuft das Projekt auf PHP 7.0-7.1, ist OpenSSL die einzige Option. In der Praxis ist es 2026 jedoch bereits schwierig, Hosting mit PHP unter 7.4 zu finden: Laut WordPress.org-Daten für Juni 2026 beträgt der Anteil von PHP 7.0-7.1 weniger als 0,3% aller Installationen.
OpenSSL oder Sodium: zwei Auswahlkriterien
Die Wahl zwischen den beiden Ansätzen läuft auf zwei Faktoren hinaus:
- PHP-Version. PHP 7.2+, nehmen Sie Sodium, es ist standardmäßig sicherer und lässt Sie bei der HMAC-Implementierung keine Fehler machen. PHP 7.0-7.1, nur OpenSSL. Unter PHP 7.0 ist es Zeit, den Server zu aktualisieren, nicht Workarounds mit PECL-mcrypt zu erfinden.
- Datenportabilität zwischen Umgebungen. OpenSSL ist überall verfügbar, einschließlich PHP 5.3+. Wenn verschlüsselte Dateien auf dem Dev-Server, in der Produktion und beim Kunden lesbar sein müssen, ist OpenSSL aus Kompatibilitätssicht zuverlässiger. Sodium-Geheimtext wird nur dort entschlüsselt, wo Sodium existiert.
In der Praxis setzen wir OpenSSL bei Projekten ein, bei denen die Kompatibilität zwischen verschiedenen Umgebungen wichtig ist. Sodium dort, wo der gesamte Stack auf PHP 8 aktualisiert ist und Sicherheit an erster Stelle steht.
Im Video erläutert Dave Hollingworth beide Ansätze im Detail mit Code-Demonstration und Erklärung der kryptografischen Grundlagen dahinter. Das Material ergänzt den Artikel: Es werden Grenzfälle gezeigt, die Installation der Bibliothek defuse/php-encryption via Composer und ein Performance-Vergleich von OpenSSL und Sodium mit echten Daten.
⁉️🤔 Häufig gestellte Fragen
Kann ich md5() oder sha1() zur Dateiverschlüsselung verwenden?
Nein.
md5()undsha1()sind Hash-Funktionen, sie sind per Definition irreversibel. Eine verschlüsselte Datei muss wieder entschlüsselt werden können, und ein Hash kann nicht entschlüsselt werden. Hashes werden zur Integritätsprüfung (wie HMAC im obigen Code) und zur Passwortspeicherung viapassword_hash()verwendet, aber nicht zur Inhaltsverschlüsselung.
Was tun, wenn der Verschlüsselungsschlüssel verloren geht?
Eine Entschlüsselung der Daten ohne den Schlüssel ist unmöglich. Speichern Sie den Schlüssel in
wp-config.phpaußerhalb des Document Root und sichern Sie ihn getrennt von Datei- und Datenbank-Backups. Legen Sie den Schlüssel nicht in einem Git-Repository ab, fügen Siewp-config.phpzu.gitignorehinzu oder verwenden Sie Umgebungsvariablen.
Warum wird ein IV benötigt, wenn der Schlüssel bereits geheim ist?
Ohne einen zufälligen IV erzeugen identische Daten, mit demselben Schlüssel verschlüsselt, identischen Geheimtext. Ein Angreifer, der sich wiederholende Blöcke sieht, erhält Informationen über die Dateistruktur. Der IV macht jeden Verschlüsselungslauf einzigartig: Dieselbe Datei, zweimal mit einem Schlüssel verschlüsselt, erzeugt zwei unterschiedliche Geheimtexte.
Kann ich große Dateien von mehreren Gigabyte verschlüsseln?
Die obigen Funktionen lesen die Datei vollständig in den Speicher, bei gigabytegroßen Daten führt dies zur Speichererschöpfung. Für eine Streaming-Verschlüsselung verwenden Sie
openssl_encrypt()in einer Schleife mit Chunk-Pufferung (z. B. je 1 MB) oder die Bibliothekdefuse/php-encryption, die den Streaming-Modus von Haus aus unterstützt.
Funktioniert dieser Code unter PHP 8.3?
Ja. Sowohl OpenSSL als auch Sodium werden in PHP 8 vollständig unterstützt. Der Code ist auf aktuellen PHP-Versionen getestet und verwendet keine veralteten Funktionen. Unter PHP 8.3 ist die Kompatibilität gewährleistet, es gibt keine Rückwärtsinkompatibilitäten in der OpenSSL-Erweiterung.
Dateiverschlüsselung 2026: praktisches Fazit
Mcrypt hat PHP verlassen, und das ist gut so. Zwei integrierte Ersatzwerkzeuge sind sowohl sicherer als auch schneller und erfordern keinen PECL-Tanz mit dem Tamburin. OpenSSL funktioniert überall, Sodium ist einfacher und standardmäßig zuverlässiger.
Kurz gesagt: Neues Projekt auf PHP 8, beginnen Sie mit Sodium, der Code wird sauberer. Migration von altem Code von mcrypt, schreiben Sie auf OpenSSL um, es ist selbst unter PHP 7.0 verfügbar. Und die Hauptregel der Kryptografie: Schlüssel getrennt von den verschlüsselten Daten aufbewahren. Schlüsselverlust bedeutet Datenverlust, und Brute-Force hilft hier nicht.
Beginnen Sie mit einem Testskript an einer Dateikopie: Stellen Sie sicher, dass der Zyklus „verschlüsselt → entschlüsselt → Byte für Byte identisch" fehlerfrei funktioniert. Und welche Methode verwenden Sie in Ihren Projekten, OpenSSL, Sodium oder etwas anderes? Schreiben Sie es in die Kommentare.



