Skip to content

Tout pour WordPress, le développement web — et plus encore

🔒 Chiffrer et déchiffrer des fichiers en PHP : OpenSSL et Sodium au lieu de mcrypt

🔒 Chiffrer et déchiffrer des fichiers en PHP : OpenSSL et Sodium au lieu de mcrypt

Chiffrer un fichier avant de le sauvegarder sur le serveur et être certain que personne, pas même l’administrateur de l’hébergement, ne peut le lire sans la clé. Cela semble être un besoin élémentaire, mais avec la disparition de mcrypt de PHP, l’approche habituelle a cessé de fonctionner.

L’extension mcrypt a été marquée comme obsolète dans PHP 7.1 et complètement supprimée dans PHP 7.2 en 2017. Aujourd’hui, sous PHP 8, tenter d’appeler mcrypt_encrypt() se termine par une erreur fatale. Pendant ce temps, des fichiers confidentiels continuent de résider sur les serveurs: sauvegardes de bases de données, CSV contenant des données personnelles, contrats PDF, exports de commandes.

Bonne nouvelle: PHP fournit deux mécanismes fonctionnels en standard, OpenSSL et Sodium. Aucun des deux ne nécessite l’installation d’une extension supplémentaire sur un hébergement moderne, et tous deux sont plus rapides et plus sûrs que mcrypt. Voici un guide pratique pour chiffrer et déchiffrer des fichiers sous PHP 8, avec du code que vous pouvez copier et exécuter.

💡 Aperçu rapide:

  • Pourquoi mcrypt est mort et quelles versions de PHP sont concernées
  • Chiffrement de fichier étape par étape via OpenSSL avec AES-256-CBC
  • Déchiffrement avec protection contre l’altération des données via HMAC
  • Alternative Sodium pour PHP 7.2 et versions ultérieures
  • Quand choisir OpenSSL et quand choisir Sodium

Pourquoi mcrypt n’est plus une option

La bibliothèque mcrypt n’a pas été mise à jour depuis 2007. Des vulnérabilités critiques ont été découvertes dans son code et aucun mainteneur n’est resté. L’équipe PHP a pris une décision: dans PHP 7.1, l’extension a été marquée comme obsolète, et dans PHP 7.2, publié en novembre 2017, elle a été complètement exclue du cœur.

Si vous migrez un ancien projet utilisant mcrypt, vérifiez phpinfo(). Sur PHP 7.2+, il n’y a pas de ligne «mcrypt support: enabled». L’appel de mcrypt_encrypt(), mcrypt_decrypt() ou des filtres de flux mcrypt.tripledes / mdecrypt.tripledes renvoie une erreur «Call to undefined function».

Techniquement, mcrypt est disponible via PECL avec la commande pecl install mcrypt. Mais installer une extension non maintenue présentant des vulnérabilités connues sur un serveur de production pour un seul script legacy est une mauvaise idée. Réécrivez le chiffrement avec OpenSSL: il est intégré à PHP depuis la version 5.3 et n’est pas près de disparaître.

Chiffrement de fichier via OpenSSL, étape par étape

OpenSSL dans PHP est représenté par les fonctions openssl_encrypt() et openssl_decrypt(). Elles travaillent avec des données brutes et prennent en charge des dizaines d’algorithmes, de AES-128-CBC à AES-256-GCM. Pour les fichiers, nous utilisons AES-256-CBC: il est cryptographiquement robuste et ne nécessite pas PHP 7.1, contrairement à GCM avec ses paramètres de balise supplémentaires.

Étape 1: générer la clé de chiffrement

La clé est le secret principal de tout le dispositif. Elle doit être cryptographiquement aléatoire, pas inventée manuellement. Pas de «mot-de-passe-secret» issu d’exemples, uniquement openssl_random_pseudo_bytes().

Le script ci-dessous génère une clé de 256 bits et l’affiche dans un format prêt à être inséré dans wp-config.php. Exécutez-le une fois en ligne de commande et conservez le résultat:

1<?php
2// Generating a random 256-bit key (32 bytes)
3$encryption_key = base64_encode(openssl_random_pseudo_bytes(32));
4echo "define('FILE_ENCRYPTION_KEY', '" . $encryption_key . "');\n";

La fonction openssl_random_pseudo_bytes(32) renvoie 32 octets d’aléa de qualité cryptographique. base64_encode convertit les données binaires en une chaîne pratique à stocker dans des fichiers de configuration. La clé doit se trouver en dehors de la racine du document, dans wp-config.php ou .env, mais pas dans le code du thème.

Étape 2: fonction de chiffrement de fichier

Le script lit un fichier depuis le disque, le chiffre avec l’algorithme AES-256-CBC, ajoute un IV aléatoire au début et une signature HMAC pour la vérification de l’intégrité, puis sauvegarde le résultat. Ajoutez le code au functions.php d’un thème enfant ou à un plugin personnalisé.

Avertissement: avant de l’exécuter sur un serveur de production, effectuez une sauvegarde complète. Testez le chiffrement-déchiffrement sur une copie du fichier dans un répertoire de test. Si la clé est perdue, le déchiffrement des données est impossible, AES-256 ne peut pas être cassé par force brute.

1<?php
2function 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}

Voici ce qui se passe ligne par ligne:

  • openssl_cipher_iv_length('aes-256-cbc') renvoie 16, la longueur du vecteur d’initialisation pour cet algorithme.
  • openssl_random_pseudo_bytes($ivLength) crée un IV aléatoire. Cela permet à des données identiques chiffrées avec la même clé de produire un texte chiffré différent à chaque exécution.
  • OPENSSL_RAW_DATA indique à la fonction de renvoyer des données binaires, et non du base64. Nous sauvegardons le texte chiffré brut par souci de compacité.
  • hash_hmac('sha256', ...) calcule une somme de contrôle à partir de l’ensemble IV et texte chiffré. Lors du déchiffrement, nous recalculerons le HMAC et comparerons: si les données ont été modifiées ou corrompues, la comparaison ne correspondra pas.
  • Le fichier est sauvegardé au format: [IV 16 bytes][HMAC 32 bytes][ciphertext]. Pas de délimiteurs, les positions sont fixes selon les longueurs.

Étape 3: fonction de déchiffrement

Le processus inverse: lire l’IV, lire le HMAC, lire le texte chiffré, recalculer le HMAC et comparer via hash_equals(), déchiffrer. Le code s’ajoute au même fichier:

1<?php
2function 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}

Point clé: hash_equals() au lieu de ===. La comparaison classique de chaînes est vulnérable aux attaques temporelles, un attaquant peut deviner le HMAC octet par octet en mesurant le temps de réponse du serveur. hash_equals() compare les chaînes en temps constant, quel que soit le caractère sur lequel elles divergent.

Exemple d’utilisation avec des chemins réels

1<?php
2$key = FILE_ENCRYPTION_KEY; // from wp-config.php
3
4// Encrypting the database backup
5encrypt_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);
13header('Content-Type: application/octet-stream');
14header('Content-Disposition: attachment; filename="backup.sql"');
15echo $decrypted;

Les fonctions sont universelles: elles fonctionnent avec tout type de fichier, images, PDF, CSV, dumps SQL. La taille est limitée uniquement par la RAM disponible, car le fichier est lu intégralement en mémoire. Pour des fichiers de plusieurs gigaoctets, un traitement par flux avec tampon par blocs sera nécessaire, mais pour l’immense majorité des cas pratiques, ce code est suffisant.

Alternative: Sodium (libsodium)

L’extension Sodium est intégrée à PHP à partir de la version 7.2 et fait partie du cœur depuis PHP 8.1. Elle fournit une API plus simple qu’OpenSSL: pas besoin de gérer manuellement l’IV et le HMAC, le chiffrement authentifié fonctionne nativement.

1<?php
2function 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
10function 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}

Remarque: Sodium vérifie l’intégrité par lui-même. Si les données ont été modifiées ou si la clé est incorrecte, sodium_crypto_secretbox_open() renvoie simplement false, aucun contrôle HMAC séparé n’est requis. Le code est deux fois plus court.

Un inconvénient: Sodium nécessite PHP 7.2 ou supérieur. Si le projet tourne sous PHP 7.0-7.1, la seule option est OpenSSL. Mais en pratique en 2026, trouver un hébergement avec une version de PHP inférieure à 7.4 est déjà difficile: selon les données de WordPress.org de juin 2026, la part de PHP 7.0-7.1 est inférieure à 0,3% de toutes les installations.

OpenSSL ou Sodium: deux critères de choix

Le choix entre les deux approches se résume à deux facteurs:

  • Version de PHP. PHP 7.2+, prenez Sodium, il est plus sûr par défaut et ne vous laisse pas la possibilité de mal implémenter le HMAC. PHP 7.0-7.1, OpenSSL uniquement. En dessous de PHP 7.0, il est temps de mettre à jour le serveur, pas d’inventer des contournements avec PECL-mcrypt.
  • Portabilité des données entre environnements. OpenSSL est disponible partout, y compris PHP 5.3+. Si les fichiers chiffrés doivent être lisibles sur le serveur de dev, en production et chez le client, OpenSSL est plus fiable du point de vue de la compatibilité. Le texte chiffré par Sodium ne se déchiffrera que là où Sodium est présent.

En pratique, nous utilisons OpenSSL sur les projets où la compatibilité entre différents environnements est importante. Sodium, là où toute la stack est à jour sous PHP 8 et où la sécurité est la priorité.

Dans la vidéo, Dave Hollingworth décortique les deux approches en détail avec une démonstration de code et une explication des primitives cryptographiques sous-jacentes. Le matériel complète l’article: les cas limites sont montrés, l’installation de la bibliothèque defuse/php-encryption via Composer et la comparaison de performance entre OpenSSL et Sodium sur des données réelles.

⁉️🤔 Foire aux questions

Puis-je utiliser md5() ou sha1() pour le chiffrement de fichiers?

Non. md5() et sha1() sont des fonctions de hachage, elles sont irréversibles par définition. Un fichier chiffré doit pouvoir être déchiffré, et un hachage ne peut pas l’être. Les hachages servent à la vérification d’intégrité (comme le HMAC dans le code ci-dessus) et au stockage des mots de passe via password_hash(), mais pas au chiffrement du contenu.

Que faire si la clé de chiffrement est perdue?

Déchiffrer les données sans la clé est impossible. Stockez la clé dans wp-config.php en dehors de la racine du document et sauvegardez-la séparément des sauvegardes de fichiers et de base de données. Ne mettez pas la clé dans un dépôt Git, ajoutez wp-config.php au .gitignore ou utilisez des variables d’environnement.

Pourquoi l’IV est-il nécessaire si la clé est déjà secrète?

Sans IV aléatoire, des données identiques chiffrées avec la même clé produisent un texte chiffré identique. Un attaquant voyant des blocs qui se répètent obtient des informations sur la structure du fichier. L’IV rend chaque opération de chiffrement unique: le même fichier chiffré deux fois avec une même clé produit deux textes chiffrés différents.

Puis-je chiffrer des fichiers volumineux, de plusieurs gigaoctets?

Les fonctions ci-dessus lisent le fichier intégralement en mémoire, pour des données de plusieurs gigaoctets, cela conduira à un épuisement de la mémoire. Pour un chiffrement par flux, utilisez openssl_encrypt() dans une boucle avec un tampon par blocs (par exemple, 1 Mo chacun) ou la bibliothèque defuse/php-encryption, qui prend en charge le mode streaming nativement.

Ce code fonctionne-t-il sur PHP 8.3?

Oui. OpenSSL et Sodium sont tous deux pleinement pris en charge sous PHP 8. Le code est testé sur les versions actuelles de PHP et n’utilise pas de fonctions obsolètes. La compatibilité avec PHP 8.3 est assurée, il n’y a pas de ruptures de compatibilité ascendante dans l’extension OpenSSL.

Le chiffrement de fichiers en 2026: verdict pratique

Mcrypt a quitté PHP, et c’est pour le mieux. Les deux outils de remplacement intégrés sont à la fois plus sûrs et plus rapides, et ne nécessitent pas de danse avec un tambourin autour de PECL. OpenSSL fonctionne partout, Sodium est plus simple et plus fiable par défaut.

En bref: nouveau projet sous PHP 8, commencez par Sodium, le code s’avère plus propre. Migration d’un ancien code depuis mcrypt, réécrivez vers OpenSSL, il est disponible même sous PHP 7.0. Et la règle d’or de la cryptographie: conservez les clés séparément des données chiffrées. La perte de la clé équivaut à la perte des données, et la force brute n’y pourra rien.

Commencez par un script de test sur une copie de fichier: assurez-vous que le cycle «chiffré → déchiffré → correspondance octet par octet» fonctionne sans erreur. Et vous, quelle méthode utilisez-vous sur vos projets, OpenSSL, Sodium ou autre chose? Écrivez-le dans les commentaires.