Chapitre 318 minIntermédiaire
Chiffrement symétrique : AES, modes et clés
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- expliquer le principe du chiffrement symétrique et ses limites ;
- choisir un algorithme et une taille de clé conformes aux règles de l'ANSSI ;
- choisir un mode : pourquoi bannir ECB et préférer GCM ;
- chiffrer et déchiffrer avec OpenSSL, PHP et Node.js ;
- calculer le nombre de clés nécessaires à un groupe.
5 exercices corrigés1 schéma
Le chiffrement symétrique utilise une seule et même clé secrète pour chiffrer et pour déchiffrer : l'expéditeur et le destinataire doivent tous deux la posséder. C'est le chiffrement le plus rapide, celui qui protège en réalité presque toutes les données, du disque de ton portable aux pages HTTPS. Ce chapitre présente AES, l'algorithme standard, les modes de chiffrement (et pourquoi le mode ECB est à bannir), le code pour chiffrer en PHP et en Node.js, et la grande limite du symétrique : l'échange des clés.
Le principe : une seule clé partagée
Le laboratoire Hélianthe chiffre les comptes rendus qu'il archive. Le même programme, avec la même clé, sert à chiffrer à l'archivage et à déchiffrer à la consultation :
clair ──[ AES + clé K ]──▶ chiffré ──[ AES + clé K ]──▶ clair
On parle aussi de chiffrement à clé secrète, par opposition au chiffrement à clé publique du chapitre 4. Ses forces et ses faiblesses tiennent en un tableau :
| Avantages | Limites |
|---|---|
| Très rapide : plusieurs gigaoctets par seconde sur un processeur actuel, grâce aux instructions AES intégrées (AES-NI sur x86, extensions équivalentes sur ARM) | Il faut transmettre la clé au destinataire avant de communiquer, par un canal sûr |
| Clés courtes : 128 ou 256 bits | Chaque paire de correspondants a besoin de sa propre clé : le nombre de clés explose |
| Adapté aux gros volumes : disques, sauvegardes, flux vidéo | Une clé partagée ne prouve pas qui a chiffré : pas de non-répudiation |
AES, le standard depuis 2001
AES (Advanced Encryption Standard) est l'algorithme de chiffrement symétrique standardisé par le NIST américain en 2001 (norme FIPS 197), à l'issue d'un concours public international. L'algorithme retenu, Rijndael, a été conçu par deux cryptologues belges, Joan Daemen et Vincent Rijmen. Il remplaçait DES (1977), dont la clé de 56 bits était devenue trop courte.
AES est un chiffrement par bloc : il découpe les données en blocs de 128 bits (16 octets) et chiffre chaque bloc par une suite de tours de substitutions, de permutations et de mélanges avec la clé.
| Variante | Taille de clé | Nombre de tours | Avis de l'ANSSI (guide de 2026) |
|---|---|---|---|
| AES-128 | 128 bits | 10 | Conforme à la règle « clé d'au moins 128 bits » |
| AES-192 | 192 bits | 12 | Conforme, et conforme à la recommandation post-quantique (au moins 192 bits) |
| AES-256 | 256 bits | 14 | Conforme aux règles et aux recommandations post-quantiques : le choix par défaut pour une protection longue |
Deux autres noms à connaître :
- ChaCha20-Poly1305, un chiffrement par flot conçu par Daniel J. Bernstein. Il est aussi sûr qu'AES-GCM et plus rapide sur les processeurs sans instructions AES (vieux téléphones, objets connectés). TLS 1.3, SSH et le VPN WireGuard l'utilisent.
- 3DES (Triple DES), qui applique trois fois DES. Il est obsolète : le NIST en interdit l'usage pour chiffrer depuis fin 2023, et l'ANSSI le juge non conforme. Si tu le croises dans une configuration (un vieux VPN, une suite TLS), c'est une non-conformité à signaler.
Chiffrement par bloc : les modes ECB, CBC, CTR et GCM
AES seul ne chiffre que 16 octets. Pour un message plus long, il faut un mode opératoire, qui dit comment enchaîner les blocs. Le choix du mode compte autant que celui de l'algorithme.
Le mode ECB (Electronic Code Book) chiffre chaque bloc indépendamment, avec la même clé. Résultat : deux blocs de clair identiques donnent deux blocs chiffrés identiques. Voici trois blocs de 16 octets chiffrés en AES-128-ECB, puis en AES-128-CBC, avec la même clé :
Clair (3 blocs) Chiffré ECB Chiffré CBC
statut=NEGATIF;; 2678b0c7a2d6d43c9f0ebb2e650cfd00 92bb39d04664ce79bddda69448ac60a0
statut=NEGATIF;; 2678b0c7a2d6d43c9f0ebb2e650cfd00 1640a847058972ce1f12e5fd8dabf0e8
statut=POSITIF;; fe677a936bbc28a44495e8af456b4061 4b22961b1f6b2ca8e2d64e5f4ec9bb63
En ECB, un espion qui ne connaît pas la clé voit que les deux premiers patients ont le même résultat et que le troisième est différent. S'il apprend un seul résultat, il connaît tous ceux qui ont le même chiffré. C'est l'analyse de fréquences des chiffrements historiques, appliquée à des blocs.
Le mode CBC (Cipher Block Chaining) combine chaque bloc clair, par XOR, avec le bloc chiffré précédent, avant de le chiffrer. Le premier bloc est combiné avec un vecteur d'initialisation (IV) de 16 octets, tiré au hasard à chaque message et transmis en clair avec le chiffré. Deux messages identiques donnent ainsi deux chiffrés différents.
Le mode CTR (compteur) chiffre un compteur (nonce + numéro de bloc) et combine le résultat au message par XOR, comme un masque. Il se parallélise bien, mais un même nonce réutilisé sous la même clé produit le même masque : c'est l'erreur du masque jetable réutilisé.
Le mode GCM (Galois/Counter Mode) est le mode CTR auquel on ajoute un calcul d'étiquette d'authentification (tag, 16 octets). Au déchiffrement, si un seul bit du chiffré, de l'IV ou du tag a été modifié, l'étiquette ne correspond plus et le déchiffrement échoue. GCM apporte donc la confidentialité et l'intégrité.
| Mode | Vecteur ou nonce | Intégrité | Verdict |
|---|---|---|---|
| ECB | Aucun | Non | À bannir : les motifs du clair transparaissent |
| CBC | IV aléatoire de 16 octets, imprévisible | Non | Acceptable avec un IV aléatoire et un contrôle d'intégrité séparé (HMAC) |
| CTR | Nonce unique | Non | Acceptable si le nonce n'est jamais réutilisé ; pas d'intégrité |
| GCM | Nonce unique de 12 octets | Oui (tag de 16 octets) | Recommandé, à condition de ne jamais réutiliser un nonce sous la même clé |
Le chiffrement authentifié : confidentialité et intégrité ensemble
Un chiffrement sans contrôle d'intégrité laisse une porte ouverte : l'attaquant ne peut pas lire, mais il peut modifier. En mode CTR, inverser un bit du chiffré inverse le même bit du clair déchiffré ; sur un champ dont il connaît la position (un montant, un code de statut), il peut changer la valeur sans connaître la clé. En mode CBC, des attaques dites « par oracle de remplissage » ont permis de déchiffrer des cookies entiers en observant simplement si le serveur répondait « remplissage invalide ».
La réponse moderne est le chiffrement authentifié (AEAD, Authenticated Encryption with Associated Data) : AES-GCM, ChaCha20-Poly1305. Il chiffre et calcule l'étiquette en une seule opération. Il peut aussi authentifier des données associées qui restent en clair, par exemple l'identifiant du patient auquel appartient un compte rendu : impossible de déplacer le chiffré d'un dossier à un autre sans que le déchiffrement échoue. Le guide de l'ANSSI le dit sans détour : il est recommandé « de ne pas employer isolément un mode opératoire de chiffrement n'offrant pas d'intégrité ».
Chiffrer en pratique : OpenSSL, PHP et Node.js
En ligne de commande, openssl enc chiffre un fichier à partir d'une phrase de passe. L'option -pbkdf2 dérive la clé de la phrase de passe avec une fonction volontairement lente, et -iter fixe le nombre d'itérations. openssl enc ne sait pas faire de chiffrement authentifié (il refuse GCM avec le message AEAD ciphers not supported) : on l'utilise en CBC, et on vérifie l'intégrité par une empreinte ou une signature.
# Chiffrer (AES-256-CBC, clé dérivée de la phrase de passe, sel aléatoire)
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 600000 \
-in compte-rendu.pdf -out compte-rendu.pdf.enc
# Déchiffrer (mêmes options, plus -d)
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 \
-in compte-rendu.pdf.enc -out compte-rendu.pdf
En PHP, l'extension OpenSSL fournit AES-GCM. La clé de 32 octets (256 bits) n'est pas dans le code : elle est lue dans une variable d'environnement, encodée en Base64. Le paquet stocké contient l'IV, l'étiquette et le chiffré.
<?php
// Clé de 32 octets générée une fois par : php -r "echo base64_encode(random_bytes(32));"
$cle = base64_decode(getenv('HELIANTHE_CLE_DONNEES'));
function chiffrer(string $clair, string $cle): string
{
$iv = random_bytes(12); // nonce unique de 12 octets
$chiffre = openssl_encrypt($clair, 'aes-256-gcm', $cle, OPENSSL_RAW_DATA, $iv, $tag);
return base64_encode($iv . $tag . $chiffre); // IV (12) + étiquette (16) + chiffré
}
function dechiffrer(string $paquet, string $cle): string|false
{
$brut = base64_decode($paquet);
$iv = substr($brut, 0, 12);
$tag = substr($brut, 12, 16);
$chiffre = substr($brut, 28);
// Renvoie false si le chiffré, l'IV ou l'étiquette ont été modifiés
return openssl_decrypt($chiffre, 'aes-256-gcm', $cle, OPENSSL_RAW_DATA, $iv, $tag);
}
PHP propose aussi l'extension Sodium (sodium_crypto_aead_xchacha20poly1305_ietf_encrypt()), plus difficile à mal utiliser, avec des nonces de 24 octets qu'on peut tirer au hasard sans crainte de collision.
En Node.js, le module intégré crypto fait la même chose :
import { randomBytes, createCipheriv, createDecipheriv } from 'node:crypto';
const cle = Buffer.from(process.env.HELIANTHE_CLE_DONNEES, 'base64'); // 32 octets
export function chiffrer(texte) {
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', cle, iv);
const chiffre = Buffer.concat([cipher.update(texte, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
return Buffer.concat([iv, tag, chiffre]).toString('base64');
}
export function dechiffrer(paquet) {
const tout = Buffer.from(paquet, 'base64');
const decipher = createDecipheriv('aes-256-gcm', cle, tout.subarray(0, 12));
decipher.setAuthTag(tout.subarray(12, 28));
// Lève l'erreur « Unsupported state or unable to authenticate data » si le paquet a été modifié
return Buffer.concat([decipher.update(tout.subarray(28)), decipher.final()]).toString('utf8');
}
Chiffre deux fois le même numéro de sécurité sociale : tu obtiens deux paquets différents, puisque l'IV change. Modifie un seul caractère du paquet : le déchiffrement échoue. C'est exactement ce qu'on attend.
Le problème de l'échange des clés
Le chiffrement symétrique suppose que les deux correspondants possèdent déjà la même clé. Comment la transmettre ? Pas par courriel, que n'importe quel serveur intermédiaire peut lire ; pas dans le même message que les données chiffrées. Et le problème grossit vite : si chaque personne d'un groupe de n personnes veut pouvoir échanger en secret avec chacune des autres, il faut une clé par paire, soit n(n − 1)/2 clés.
| Personnes | Clés symétriques nécessaires |
|---|---|
| 2 | 1 |
| 10 | 45 |
| 50 | 1 225 |
| 140 (les salariés d'Hélianthe) | 9 730 |
Le chiffrement asymétrique résout ce problème : chacun publie une clé publique, et deux inconnus peuvent convenir d'une clé secrète sur un réseau espionné (Diffie-Hellman). En pratique, on combine les deux : l'asymétrique échange la clé, le symétrique chiffre les données. C'est le chiffrement hybride de TLS, de SSH et de PGP.
Une fois la clé en place, il faut la garder. Une clé de chiffrement ne s'écrit jamais dans le code source ni dans un dépôt Git (cours Git et GitHub) : elle vit dans une variable d'environnement du serveur, un coffre de secrets, ou un module matériel (HSM, TPM). Une clé perdue rend les données irrécupérables : elle se sauvegarde, à part des données qu'elle protège.
À l'E7 : comment la notion est demandée
- Chiffrer une colonne dans le SGBD. Le sujet SLAM 2026 (cas NDV) fait chiffrer les adresses électroniques des contacts avec
AES_ENCRYPT(), en passant la colonne enVARBINARY(200), puis corriger une requête préparée pour réafficher l'adresse en clair avecAES_DECRYPT(), la clé étant lue dans une variable d'environnement. Le sujet SLAM 2024 (cas Gsic) fait chiffrer des colonnes sensibles d'une base SQL Server avec une clé symétriqueAES_256protégée par un certificat. Le cours SQL déroule les deux syntaxes (chiffrer une colonne sensible). - Justifier un paramètre de sécurité. Le sujet SISR 2025 (cas Blanca) demande d'expliquer les deux paramètres qui sécurisent SNMPv3 dans la commande
snmpv3 user <username> auth sha <password> priv aes <priv password>:priv aesactive le chiffrement symétrique AES des messages, donc leur confidentialité ;auth shaassure l'authentification et l'intégrité (HMAC). - Proposer un scénario de risque qui rend le chiffrement pertinent : une sauvegarde volée, un administrateur de base curieux, une injection SQL qui exfiltre la table. Le chiffrement protège la confidentialité si la clé n'est pas au même endroit que les données.
En SLAM, le réflexe : AES-256-GCM, clé hors du code, IV aléatoire stocké avec le chiffré. En SISR, le réflexe : désactiver les suites et protocoles à 3DES ou RC4, préférer AES-GCM ou ChaCha20 dans les VPN et les services.
Pour aller plus loin. Les erreurs de chiffrement côté application (clé dans le code, mode ECB, algorithme maison) sont classées dans l'OWASP Top 10 : voir le chapitre Défaillances cryptographiques (A04) du cours Sécurité applicative.
Exercices
Exercice 1 sur 5 Que révèle ce chiffré ? Réussi À revoir
Une table stocke le résultat d'un test, chiffré avec AES_ENCRYPT() et la même clé pour tous les patients. Tu observes que 812 lignes ont exactement le même chiffré 0x2678B0C7…, et 37 lignes un autre chiffré.
- Quel mode de chiffrement est utilisé, et comment le sais-tu ?
- Quelle information fuit sans que l'attaquant connaisse la clé ?
- Propose une correction.
Voir la réponseMasquer la réponse de l'exercice 1
- Le mode ECB, celui de
AES_ENCRYPT()par défaut : des clairs identiques donnent des chiffrés identiques, ce qui n'arrive pas avec un mode qui utilise un IV aléatoire. - La répartition des résultats : 812 patients ont le même résultat, 37 un autre. Si l'attaquant connaît le résultat d'un seul patient (le sien, par exemple), il connaît celui de tous les patients qui partagent son chiffré.
- Utiliser un mode avec vecteur d'initialisation aléatoire stocké avec la donnée (
SET block_encryption_mode = 'aes-256-cbc'etAES_ENCRYPT(valeur, @cle, @iv)), ou mieux, chiffrer dans l'application en AES-256-GCM, avec une clé gardée hors de la base.
Tu avais trouvé ?
Exercice 2 sur 5 Combien de clés ? Réussi À revoir
- Combien de clés symétriques faut-il pour que 20 techniciens puissent tous communiquer deux à deux en secret ?
- Un 21ᵉ technicien arrive. Combien de clés faut-il ajouter ?
- Quelle solution évite cette explosion ?
Voir la réponseMasquer la réponse de l'exercice 2
- 20 × 19 / 2 = 190 clés.
- Le nouveau doit partager une clé avec chacun des 20 autres : 20 clés de plus (21 × 20 / 2 = 210).
- La cryptographie asymétrique : chacun a une paire de clés, soit 21 paires, et les clés symétriques de session sont échangées à la demande (chiffrement hybride, Diffie-Hellman).
Tu avais trouvé ?
Exercice 3 sur 5 Revue de code Réussi À revoir
Un développeur propose ce code pour chiffrer les numéros de sécurité sociale :
$cle = 'helianthe2026';
$iv = '0000000000000000';
$chiffre = openssl_encrypt($nss, 'aes-256-cbc', $cle, 0, $iv);
Relève trois défauts et propose une version corrigée.
Voir la réponseMasquer la réponse de l'exercice 3
- La clé est écrite dans le code : quiconque lit le dépôt ou le serveur la connaît. Elle doit venir d'une variable d'environnement ou d'un coffre de secrets.
- La clé n'en est pas une : une chaîne de 13 caractères devinable, au lieu de 32 octets aléatoires générés par
random_bytes(32). - L'IV est fixe : deux numéros identiques donnent deux chiffrés identiques ; l'IV doit être aléatoire, différent à chaque chiffrement, et stocké avec le chiffré.
- (Bonus) CBC sans intégrité : un attaquant peut modifier le chiffré sans être détecté ; préférer AES-256-GCM.
Correction : la fonction chiffrer() de ce chapitre, avec $cle = base64_decode(getenv('HELIANTHE_CLE_DONNEES')), un IV de random_bytes(12) et le mode aes-256-gcm.
Tu avais trouvé ?
Exercice 4 sur 5 Force brute sur AES Réussi À revoir
Une machine teste 10¹² clés par seconde. Combien de temps lui faut-il, au pire, pour essayer toutes les clés AES-128 ? Et toutes les clés DES ? Une année compte environ 3,16 × 10⁷ secondes.
Voir la réponseMasquer la réponse de l'exercice 4
- AES-128 : 2¹²⁸ ≈ 3,4 × 10³⁸ clés ; 3,4 × 10³⁸ / 10¹² = 3,4 × 10²⁶ secondes, soit 3,4 × 10²⁶ / 3,16 × 10⁷ ≈ 1,1 × 10¹⁹ années. Hors de portée.
- DES : 2⁵⁶ ≈ 7,2 × 10¹⁶ clés ; 7,2 × 10¹⁶ / 10¹² = 72 000 secondes, soit 20 heures. C'est pour cela que DES est abandonné.
Tu avais trouvé ?
Exercice 5 sur 5 Le bon mode Réussi À revoir
Pour chaque situation, indique le mode (ECB, CBC, GCM) que tu choisis, ou celui que tu refuses, et pourquoi.
- Chiffrer les messages d'une API où un attaquant pourrait modifier les montants en transit.
- Chiffrer avec
openssl encune archive de sauvegarde avant de l'envoyer sur un stockage externe. - Un prestataire propose de chiffrer une colonne de codes postaux en ECB « parce que c'est plus simple ».
Voir la réponseMasquer la réponse de l'exercice 5
- GCM : il apporte l'intégrité, la modification d'un seul bit fait échouer le déchiffrement.
- CBC (ou CTR) avec
openssl enc, qui refuse les modes authentifiés comme GCM : avec-pbkdf2et un sel aléatoire ; on calcule en plus une empreinte SHA-256 de l'archive, conservée à part, pour contrôler l'intégrité à la restauration. - Refuser ECB : il y a peu de codes postaux différents, donc beaucoup de chiffrés identiques, et l'analyse de fréquences permet de retrouver les plus courants (les villes du siège et des laboratoires).
Tu avais trouvé ?