CBC (Cipher Block Chaining, NIST SP 800-38A en 2001) et GCM (Galois/Counter Mode, NIST SP 800-38D en 2007) sont deux modes d'opération pour chiffrement par blocs (typiquement AES). Leur différence fondamentale : CBC fournit uniquement la confidentialité et exige un MAC séparé pour l'intégrité, tandis que GCM est un mode AEAD (Authenticated Encryption with Associated Data) qui combine chiffrement + authentification en une seule opération. En 2026, GCM domine largement (TLS 1.3 impose AEAD depuis août 2018, RFC 8446) tandis que CBC est en déclin progressif suite à une longue série d'attaques cryptographiques marquantes (BEAST 2011, Lucky 13 2013, POODLE 2014, padding oracles génériques de Vaudenay 2002). Cet article détaille les mécanismes de CBC et GCM, leurs différences pratiques (performance, parallélisation, padding, tags d'authentification), pourquoi CBC est devenu dangereux malgré sa robustesse théorique, pourquoi GCM est recommandé par défaut, les pièges spécifiques GCM (réutilisation de nonce catastrophique), les performances comparées avec AES-NI/AVX (GCM 5-10x plus rapide), la migration CBC → GCM dans les systèmes existants, les alternatives modernes (ChaCha20-Poly1305, AES-GCM-SIV résistant au nonce reuse), et les cas d'usage 2026 par mode.
Rappel : block ciphers et modes d'opération
AES (Advanced Encryption Standard) est un block cipher : il chiffre un bloc fixe de 128 bits (16 octets) à la fois. Pour chiffrer un message plus long, il faut un mode d'opération qui décrit comment combiner les blocs.
Modes d'opération courants
| Mode | Année | Description | Statut 2026 |
|---|---|---|---|
| ECB (Electronic Codebook) | 1981 | Chiffrement bloc par bloc indépendant | Interdit (déterministe, fuites patterns) |
| CBC (Cipher Block Chaining) | 1981 | Chaque bloc XOR avec précédent chiffré + IV | Déprécié pour nouveaux usages |
| CFB (Cipher Feedback) | 1981 | Stream-like via feedback | Rare 2026 |
| OFB (Output Feedback) | 1981 | Stream-like via feedback | Rare 2026 |
| CTR (Counter) | 1981 / utilisé 2000+ | Compteur chiffré → keystream XOR | Composant GCM |
| XTS (XEX with tweak and ciphertext stealing) | 2007 | Chiffrement disque | Standard chiffrement disque |
| GCM (Galois/Counter Mode) | 2007 | CTR + Galois MAC = AEAD | Recommandé 2026 |
| CCM (Counter with CBC-MAC) | 2002 | Counter + CBC-MAC pour AEAD | Niche IoT (Bluetooth LE, WPA2) |
| OCB (Offset Codebook) | 2003 | AEAD optimisé performance | Émergent, RFC 7253 |
| AES-GCM-SIV | 2017 (RFC 8452) | GCM-SIV résiste nonce reuse | Recommandé pour cas spécifiques |
En 2026, GCM et AES-GCM-SIV dominent les nouveaux usages, suivis de ChaCha20-Poly1305 (algorithme stream pas mode AES, mais AEAD équivalent).
Pourquoi pas seulement AES "tout court" ?
AES seul n'est pas un système de chiffrement utilisable : il chiffre uniquement un bloc 128 bits. Pour un message de 1000 octets, il faut découper en 63 blocs de 16 octets et appliquer un mode pour les enchaîner sans révéler de patterns.
Mode ECB illustre le danger : chaque bloc identique en plaintext = même bloc en ciphertext. Pour une image bitmap chiffrée en ECB, les patterns visuels sont préservés (image célèbre du pingouin Tux ECB).
CBC : Cipher Block Chaining
Mode historique le plus déployé jusqu'aux années 2010. Standardisé par NIST SP 800-38A en 2001 (mais inventé en 1976).
Mécanisme
Plaintext blocks: P1, P2, P3, ..., Pn
IV: random 16 octets
C1 = AES_encrypt(K, P1 XOR IV)
C2 = AES_encrypt(K, P2 XOR C1)
C3 = AES_encrypt(K, P3 XOR C2)
...
Cn = AES_encrypt(K, Pn XOR Cn-1)
Ciphertext: IV | C1 | C2 | C3 | ... | CnChaque bloc dépend du précédent. Décryption :
P1 = AES_decrypt(K, C1) XOR IV
P2 = AES_decrypt(K, C2) XOR C1
...
Pn = AES_decrypt(K, Cn) XOR Cn-1Padding obligatoire
Comme AES exige des blocs de 16 octets exacts, le dernier bloc doit être paddé. Standard PKCS#7 :
- Si message exact multiple de 16 : ajouter un bloc complet de padding (16 octets à 0x10).
- Si message a 5 octets restant : ajouter 11 octets de valeur 0x0B.
- Si message a 1 octet restant : ajouter 15 octets de valeur 0x0F.
Ce padding doit être validé à la décryption. Source de la classe d'attaques padding oracle.
CBC seul ne fournit pas l'intégrité
CBC chiffre mais ne vérifie pas que le ciphertext n'a pas été modifié. Pour intégrité, il faut un MAC séparé :
ciphertext = AES-CBC(key_enc, IV, plaintext + padding)
mac = HMAC-SHA256(key_mac, IV || ciphertext)
output = IV || ciphertext || macConstruction recommandée : Encrypt-then-MAC (E&M ou MAC-then-Encrypt sont vulnérables).
Forces de CBC
- Compatible large : supporté partout depuis les années 1980.
- Implémentations matures, bibliothèques nombreuses.
- Acceptable si correctement utilisé avec MAC séparé.
Faiblesses critiques
- Padding obligatoire = surface d'attaque (padding oracle).
- Séquentiel (chiffrement non parallélisable).
- IV doit être aléatoire et imprévisible (sinon BEAST).
- Sans MAC = ciphertext malléable.
GCM : Galois/Counter Mode
Mode AEAD moderne. Standardisé par NIST SP 800-38D en 2007. Adopté massivement post-2010.
Mécanisme simplifié
GCM combine deux composants :
- CTR mode pour chiffrement (stream cipher dérivé de AES).
- GHASH (Galois MAC) pour authentification.
Inputs:
- Key K (128 ou 256 bits)
- Nonce/IV (12 octets recommandé)
- Plaintext P
- Additional Authenticated Data (AAD) optional
Counter = nonce | 0x00000001
J0 = nonce | 0x00000002 (initial counter)
For each block i:
Ki = AES_encrypt(K, J0 + i) # keystream block
Ci = Pi XOR Ki # chiffrement = XOR
Tag = GHASH(K, AAD, ciphertext) XOR AES_encrypt(K, J0)
Output: Ciphertext + Tag (16 octets)GHASH utilise multiplication dans Galois Field GF(2^128) pour calculer le tag d'authentification.
Pas de padding nécessaire
GCM agit comme un stream cipher (XOR avec keystream). Le ciphertext a exactement la même taille que le plaintext, plus 16 octets de tag d'authentification. Pas de padding = pas de padding oracle attack.
AEAD : authentification intégrée
Le tag GHASH garantit qu'aucun bit n'a été modifié dans :
- Le ciphertext (intégrité du message).
- L'AAD (Additional Authenticated Data, données associées non chiffrées mais authentifiées).
- Le nonce.
À la décryption, le tag est vérifié AVANT toute exposition du plaintext. Si tag invalide, opération échoue, plaintext jamais révélé.
Forces de GCM
- AEAD natif : confidentialité + intégrité + authentification AAD en une opération.
- Parallélisable (CTR mode + GHASH parallel).
- Performance excellente avec AES-NI + PCLMULQDQ (Intel since 2010).
- Pas de padding (immune padding oracle).
- Standard universel TLS 1.2 et 1.3.
Faiblesse critique : nonce reuse
Réutiliser un nonce avec la même clé est catastrophique :
- Compromission complète confidentialité (XOR des deux ciphertexts révèle XOR des plaintexts).
- Compromission complète intégrité (l'attaquant peut récupérer la clé d'authentification H et forger des messages).
Cette faiblesse est intrinsèque à GCM. Mitigations : nonce déterministe avec compteur, ou AES-GCM-SIV.
Comparaison technique côte à côte
Différences clés pour décision rapide.
| Dimension | CBC | GCM |
|---|---|---|
| Type | Mode chiffrement seul | AEAD (chiffrement + authentification) |
| Confidentialité | Oui | Oui |
| Intégrité | Non (MAC séparé requis) | Oui (intégrée) |
| Authentification AAD | Non | Oui |
| Padding | Obligatoire (PKCS#7 standard) | Non (stream cipher) |
| IV / Nonce taille | 16 octets recommandé | 12 octets recommandé |
| IV / Nonce génération | Aléatoire imprévisible | Unique (jamais réutiliser) |
| Parallélisation chiffrement | Non (séquentiel) | Oui |
| Parallélisation déchiffrement | Oui | Oui |
| Tag d'authentification | Externe (HMAC) typiquement 32 octets | Intégré 16 octets |
| Performance avec AES-NI | Limité par séquentialité | Excellent (5-10 GB/s) |
| Padding oracle vulnérable | Oui (si mauvaise implémentation) | Non (pas de padding) |
| Standardisation | NIST SP 800-38A (2001) | NIST SP 800-38D (2007) |
| TLS 1.3 supporté | Non (CBC supprimé) | Oui (recommandé) |
| Statut 2026 | Déprécié pour nouveaux usages | Recommandé par défaut |
Pourquoi CBC est devenu dangereux
L'historique de CBC montre une accumulation d'attaques exploitables qui ont mené à sa dépréciation pratique.
Padding oracle attacks (Vaudenay 2002)
Serge Vaudenay publie en 2002 "Security Flaws Induced by CBC Padding". L'attaque exploite le fait que la décryption avec padding invalide peut révéler des informations via timing, error messages, ou comportement applicatif différent.
Mécanique : l'attaquant modifie le ciphertext, observe la réponse serveur (erreur padding vs erreur autre vs succès), et peut récupérer le plaintext octet par octet via environ 256 requêtes par octet.
Variantes ultérieures :
- Lucky 13 (CVE-2013-0169, 2013) : timing attack sur HMAC dans TLS CBC.
- POODLE (CVE-2014-3566, 2014) : padding oracle sur SSL 3.0 CBC.
- GOLDENDOODLE (2018) : variant moderne.
BEAST (CVE-2011-3389, 2011)
Browser Exploit Against SSL/TLS. Exploite IV prévisible dans TLS 1.0 CBC : l'IV du message N est le dernier bloc chiffré du message N-1, donc connu de l'attaquant.
L'attaquant injecte plaintext choisi dans la session (via JavaScript) et peut récupérer cookie HTTPS via attaque blockwise-adaptive chosen plaintext.
Mitigation : 1/n-1 split (split première requête CBC), puis migration TLS 1.1+ qui utilise IV aléatoire par record.
POODLE (CVE-2014-3566, 2014)
Padding Oracle On Downgraded Legacy Encryption. Attaque sur SSL 3.0 CBC. Force le navigateur à fallback vers SSL 3.0 (vulnerable) puis exploite padding oracle.
Mitigation : désactivation SSL 3.0 partout. RFC 7568 formalise interdiction (juin 2015).
Lucky 13 (CVE-2013-0169, 2013)
Timing attack sur HMAC dans TLS CBC. Différence de timing imperceptible (~10ns) mais mesurable sur réseau permet de distinguer ciphertext valide vs invalide.
Mitigation : implémentation constant-time de HMAC + padding check. Difficile à faire correctement.
CBC Bit-Flipping
Modification d'un bit du ciphertext bloc N change le bloc plaintext N+1 de manière prévisible (XOR). Sans MAC, ciphertext malléable.
Conclusion CBC
CBC théoriquement sécurisé mais pratiquement difficile à implémenter correctement. La quantité d'attaques découvertes en 13 ans (2002-2015) montre que les développeurs et même les implémenteurs de bibliothèques crypto échouent régulièrement à éviter les pièges. AEAD GCM élimine ces classes par construction.
Pourquoi GCM est sécurisé
GCM résout les problèmes de CBC par design.
AEAD natif : pas de MAC séparé
Pas de risque de combiner MAC mauvaisement (MAC-then-Encrypt vulnérable). Pas de risque d'oublier le MAC. AEAD garantit chiffrement + authentification en une opération atomique.
Pas de padding
Stream cipher : ciphertext même taille que plaintext. Pas de padding oracle attack possible.
Tag fail-closed
Si le tag d'authentification ne vérifie pas, l'opération échoue avant tout traitement du plaintext. Pas d'oracle.
Standardisation forte
NIST SP 800-38D définit GCM rigoureusement. RFC 8446 (TLS 1.3) impose AEAD uniquement. Adoption universelle force l'implémentation soignée.
Vérification de tag constant-time
Les implémentations modernes utilisent CRYPTO_memcmp ou équivalent constant-time pour comparer tags. Pas de timing attack sur la vérification.
Performance comparée
Benchmarks 2026 sur CPU moderne avec AES-NI + PCLMULQDQ.
AES-128 modes single thread
| Mode | Throughput | Notes |
|---|---|---|
| AES-128-ECB | 2-4 GB/s | Parallélisable, dangereux |
| AES-128-CBC encrypt | 1-2 GB/s | Séquentiel chiffrement |
| AES-128-CBC decrypt | 4-8 GB/s | Parallélisable décryption |
| AES-128-CTR | 4-10 GB/s | Parallélisable |
| AES-128-GCM | 5-10 GB/s | CTR + GHASH parallèles |
| AES-128-OCB | 6-12 GB/s | Plus rapide que GCM, RFC 7253 |
| AES-256-GCM | 4-8 GB/s | Légèrement plus lent que 128 |
| ChaCha20-Poly1305 | 2-4 GB/s | Pure software, pas AES-NI requis |
GCM 5-10x plus rapide que CBC en chiffrement, équivalent en déchiffrement. Sur serveur TLS haute charge (millions de connexions/sec), différence devient critique.
Pourquoi GCM exploite mieux CPU moderne
- AES-NI (Intel/AMD depuis 2010) : instructions matérielles AES.
- PCLMULQDQ (Intel depuis 2010) : multiplication carry-less 64x64, accélère GHASH.
- AVX-512 (Intel depuis 2017) : vectorisation lourde.
- Parallélisation CTR : chaque bloc chiffré indépendamment.
Ces optimisations bénéficient à GCM et CTR. CBC chiffrement séquentiel ne peut pas en profiter.
Pièges spécifiques à GCM
GCM résout les problèmes CBC mais introduit ses propres pièges critiques.
Piège 1 — Réutilisation de nonce
Le piège le plus dangereux. Réutiliser un nonce avec la même clé :
- Compromet confidentialité : XOR des deux ciphertexts révèle XOR des deux plaintexts. L'attaquant connaît un des deux = il connaît l'autre.
- Compromet intégrité : l'attaquant peut récupérer la clé d'authentification H = forger des messages.
Catastrophique total.
Comment éviter le nonce reuse
Méthode 1 — Compteur déterministe (recommandé pour serveur)
# Pseudo-code
counter = 0 # persistent storage critical
def encrypt(plaintext):
global counter
counter += 1
nonce = counter.to_bytes(12, byteorder='big')
ciphertext, tag = AES_GCM.encrypt(key, nonce, plaintext)
return nonce + ciphertext + tagStockage persistent du compteur critique. Crash + redémarrage SANS sync = nonce réutilisé = catastrophe.
Méthode 2 — Nonce aléatoire 96 bits (acceptable si volume limité)
import secrets
def encrypt(plaintext):
nonce = secrets.token_bytes(12)
ciphertext, tag = AES_GCM.encrypt(key, nonce, plaintext)
return nonce + ciphertext + tagBirthday paradox : pour 2^32 messages avec même clé, probabilité collision ~50 %. Donc rotation de clé requise après quelques milliards de messages.
Méthode 3 — AES-GCM-SIV (résistant nonce reuse)
Si garantir nonce unique est difficile (environnement distribué, multi-master, edge), utiliser AES-GCM-SIV qui dégrade gracieusement en cas de nonce reuse.
Piège 2 — Tag tronqué
Tag GCM standard : 16 octets (128 bits). Certaines spécifications permettent tags plus courts (96, 104, 112 bits). Ne pas utiliser : sécurité dégradée linéairement.
Piège 3 — Manque d'AAD
L'AAD (Additional Authenticated Data) protège des données associées non chiffrées (par exemple : header HTTP, métadonnées). Oublier d'inclure ces données dans l'AAD permet à l'attaquant de modifier le contexte associé sans détection.
# Vulnérable : context non authentifié
ciphertext, tag = AES_GCM.encrypt(key, nonce, plaintext)
# Sécurisé : context authentifié
context = b"user:42|action:transfer|amount:1000"
ciphertext, tag = AES_GCM.encrypt(key, nonce, plaintext, aad=context)Piège 4 — Réutilisation de clé long-terme
Même avec nonces uniques, une clé GCM ne devrait pas chiffrer indéfiniment. Limites NIST SP 800-38D :
- Maximum 2^39 octets (~500 GB) avec une seule clé GCM.
- Au-delà, rotation de clé obligatoire.
Pour TLS, rotation par session (handshake = nouvelle clé) résout naturellement.
Cas d'usage par mode 2026
Recommandations selon contexte.
| Cas d'usage | Mode recommandé |
|---|---|
| TLS 1.3 (serveur web) | AES-128-GCM ou ChaCha20-Poly1305 |
| TLS 1.2 moderne | AES-128-GCM-SHA256 ou ChaCha20-Poly1305-SHA256 |
| API JWT signing | EdDSA ou ES256 (pas chiffrement, mais AEAD si JWE) |
| Application-level encryption | libsodium crypto_secretbox (XChaCha20-Poly1305) |
| Chiffrement de fichiers | age (X25519 + ChaCha20-Poly1305) |
| Chiffrement de disque | XTS-AES (LUKS Linux, FileVault macOS, BitLocker Windows) |
| Wireguard VPN | ChaCha20-Poly1305 |
| Backup chiffré | AES-256-GCM ou ChaCha20-Poly1305 |
| Database column encryption | AES-256-GCM ou AES-GCM-SIV (si nonces distribués) |
| Session cookies | AES-256-GCM dans iron-session, secure-cookie patterns |
| Bluetooth LE | AES-128-CCM (standard imposé) |
| WPA3 Wi-Fi | AES-128-CCM (standard imposé) |
| Embedded contraint | AES-128-CCM si AEAD obligatoire et CCM standard |
CBC quasi jamais recommandé en 2026 sauf compatibilité legacy stricte avec validation Encrypt-then-MAC + protections side-channel rigoureuses.
Migration CBC vers GCM
Plan de migration pour systèmes existants.
Étape 1 — Inventaire
Identifier tous les usages CBC :
- Configuration TLS serveurs (nginx, Apache, HAProxy, application servers).
- Bibliothèques applicatives (Java JCE, .NET RijndaelManaged, Python cryptography legacy code).
- Format de fichiers chiffrés au repos.
- Protocoles custom interne.
- Bases de données avec column encryption.
Étape 2 — Évaluation de compatibilité
Vérifier que tous les consommateurs supportent AEAD :
- TLS clients : tous les navigateurs 2014+ supportent AES-GCM.
- Bibliothèques applicatives : check version.
- Formats de fichiers : besoin format hybride pour transition.
Étape 3 — Configuration TLS Modern
# nginx Mozilla Modern : élimine CBC
ssl_protocols TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;Pour TLS 1.2 transitionnel :
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;Étape 4 — Migration application-level
Pour code applicatif chiffrant en CBC :
# Avant : CBC
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hmac, hashes
def encrypt_cbc(key_enc, key_mac, plaintext):
iv = secrets.token_bytes(16)
padded = pkcs7_pad(plaintext)
cipher = Cipher(algorithms.AES(key_enc), modes.CBC(iv))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(padded) + encryptor.finalize()
h = hmac.HMAC(key_mac, hashes.SHA256())
h.update(iv + ciphertext)
mac = h.finalize()
return iv + ciphertext + mac
# Après : GCM
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
def encrypt_gcm(key, plaintext, aad=b""):
aesgcm = AESGCM(key)
nonce = secrets.token_bytes(12)
ciphertext = aesgcm.encrypt(nonce, plaintext, aad)
return nonce + ciphertext # ciphertext inclut tag déjàÉtape 5 — Format hybride pour migration progressive
Pour données chiffrées au repos, format hybride supporte ancien CBC ET nouveau GCM :
# Versioned format
VERSION_CBC = 0x01
VERSION_GCM = 0x02
def decrypt(blob):
version = blob[0]
if version == VERSION_CBC:
return decrypt_cbc(blob[1:])
elif version == VERSION_GCM:
return decrypt_gcm(blob[1:])
else:
raise ValueError("Unknown encryption version")
# Tous nouveaux chiffrements en GCM
def encrypt(plaintext):
encrypted = encrypt_gcm(plaintext)
return bytes([VERSION_GCM]) + encryptedÉtape 6 — Re-encryption batch (optionnel)
Pour migrer données existantes vers GCM :
# Background job processing
for record in db.query("SELECT * FROM encrypted_data WHERE version = 1"):
plaintext = decrypt_cbc(record.ciphertext)
new_ciphertext = encrypt_gcm(plaintext)
db.execute(
"UPDATE encrypted_data SET ciphertext = ?, version = 2 WHERE id = ?",
new_ciphertext, record.id
)Coût : peut prendre jours/semaines pour gros volumes. Faire en background sans impacter charge production.
Alternatives modernes
GCM n'est pas le seul AEAD moderne. Alternatives recommandables.
ChaCha20-Poly1305
Stream cipher AEAD, pas mode AES. Inventé par Daniel Bernstein.
Forces :
- Pure software, pas besoin AES-NI.
- Performance excellente sur ARM (mobile, Apple Silicon).
- Constant-time par design.
- Standardisé RFC 7539 / RFC 8439.
Cas d'usage :
- TLS 1.3 cipher suite TLS_CHACHA20_POLY1305_SHA256.
- Mobile apps (préféré sur Android, iOS).
- Wireguard VPN.
- libsodium crypto_secretbox (XChaCha20-Poly1305 variant avec nonce 192 bits).
AES-GCM-SIV (RFC 8452, 2019)
Variante de GCM résistante au nonce reuse. Adam Langley (Google).
Forces :
- Si nonce reused, dégradation gracieuse (les deux messages avec même nonce révèlent que les plaintexts sont identiques, mais rien d'autre).
- Pas de récupération de clé d'authentification.
- Trade-off : ~2x plus lent que AES-GCM standard.
Cas d'usage :
- Environnements distribués où coordination de nonces est difficile.
- Bibliothèques pour développeurs novices (limite les bugs).
- Multi-master databases avec sync intermittent.
Adopté par Google pour stocker tokens, Cloudflare pour certains usages internes.
XChaCha20-Poly1305
Variant ChaCha20-Poly1305 avec nonce étendu à 192 bits (24 octets) au lieu de 96 bits (12 octets).
Forces :
- Nonce 192 bits = nonce aléatoire totalement safe (pas de risque collision birthday).
- Performance similaire ChaCha20-Poly1305.
Cas d'usage :
- libsodium crypto_secretbox par défaut.
- age file encryption.
- Standards modernes pour application-level encryption.
OCB (Offset Codebook, RFC 7253)
AEAD basé sur AES, plus rapide que GCM. Inventé par Phil Rogaway.
Limitation historique : brevet de Rogaway expirait 2021. Maintenant libre. Adoption croissante dans certains contextes embedded haute performance.
Outils de test
Comment auditer la configuration des modes en pratique.
Test TLS
# testssl.sh : audit des cipher suites
./testssl.sh --ciphers https://example.test
# Cherche présence de cipher suites CBC dans output
# Si présentes, vulnérables à BEAST/POODLE/Lucky 13
# Mozilla Observatory
# observatory.mozilla.org : note A+ exige modern profile (no CBC)Test application-level
Vérifier code source pour usages CBC obsolètes :
# Recherche utilisations Python cryptography legacy
grep -rn "modes.CBC" .
grep -rn "AES.MODE_CBC" .
# Recherche Java JCE legacy
grep -rn "AES/CBC" .
# Recherche Node.js legacy
grep -rn "createCipheriv.*aes-.*-cbc" .Migrer chaque occurrence vers AEAD (GCM ou ChaCha20-Poly1305).
Anti-patterns CBC à corriger
Cinq erreurs récurrentes sur code legacy.
1. CBC sans MAC
# Vulnérable : pas de MAC
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
ciphertext = cipher.encryptor().update(plaintext) + cipher.encryptor().finalize()Solution : ajouter HMAC ou migrer vers GCM.
2. MAC-then-Encrypt
# Vulnérable : MAC sur plaintext, puis chiffrement (pas Encrypt-then-MAC)
mac = hmac.new(key_mac, plaintext, hashes.SHA256()).digest()
ciphertext = encrypt_cbc(key_enc, plaintext + mac)Solution : Encrypt-then-MAC (ou mieux : GCM).
3. IV prévisible
# Vulnérable : IV prévisible (compteur sequentiel)
counter += 1
iv = counter.to_bytes(16, 'big')Solution : IV aléatoire avec PRNG cryptographique (secrets.token_bytes(16)).
4. IV partagé entre messages
# Vulnérable : même IV pour plusieurs messages
SHARED_IV = b"0123456789ABCDEF"
ciphertext = encrypt_cbc(key, SHARED_IV, plaintext)Solution : IV unique par message.
5. Validation padding non constant-time
Lucky 13 et padding oracles exploitent timing dans validation padding. Implémentation correcte exige constant-time, complexe à coder soi-même.
Solution : utiliser bibliothèques de haut niveau (libsodium, cryptography Python) qui font correctement.
Quand CBC reste acceptable en 2026
Cinq cas où CBC peut encore être utilisé.
1. Standards historiques imposés
PCI-DSS legacy, certains standards bancaires, équipements embarqués certifiés FIPS qui n'ont pas migré vers AEAD.
2. Compatibilité backward exigée
Système legacy qui ne peut pas être mis à jour, intégration partner B2B avec format CBC fixé.
3. AES-CBC + HMAC-SHA256 Encrypt-then-MAC bien implémenté
Cryptographiquement valide si :
- Encrypt-then-MAC (jamais MAC-then-Encrypt).
- IV aléatoire imprévisible par message.
- Padding PKCS#7 standard.
- Validation constant-time (cryptography library).
- Vérification MAC AVANT décryption.
Mais : préférer AEAD natif (GCM) qui élimine ces classes de bugs par design.
4. Chiffrement de disque XTS
XTS (XEX with tweak and ciphertext stealing) est dérivé de CBC mais conçu spécifiquement pour disques. Utilisé par LUKS Linux, FileVault macOS, BitLocker Windows. Acceptable et standard pour ce cas d'usage.
5. Tests et compatibilité
Code de test pour vérifier compatibilité legacy. Pas chiffrement de production.
Hors ces cas, GCM ou ChaCha20-Poly1305 partout en 2026.
Points clés à retenir
- CBC (NIST SP 800-38A 2001) et GCM (NIST SP 800-38D 2007) sont deux modes d'opération AES distincts. CBC fournit confidentialité seulement, GCM est AEAD (confidentialité + intégrité + authentification).
- En 2026, GCM domine et CBC est déprécié pour nouveaux usages. TLS 1.3 (août 2018) impose AEAD uniquement, supprimant CBC. Adoption massive dans tous protocoles modernes.
- CBC vulnérable à de nombreuses attaques cryptographiques : padding oracle (Vaudenay 2002), BEAST (CVE-2011-3389), Lucky 13 (CVE-2013-0169), POODLE (CVE-2014-3566). Implémentation correcte difficile.
- GCM résout ces problèmes par construction (pas de padding, AEAD intégré, parallélisation native AES-NI/PCLMULQDQ). Performance 5-10x supérieure à CBC sur CPU moderne.
- Piège GCM critique : nonce reuse catastrophique (compromet confidentialité + intégrité). Solutions : nonce déterministe via compteur, ou AES-GCM-SIV (RFC 8452) qui résiste au nonce reuse.
Pour aller plus loin
- Chiffrement symétrique expliqué - vue d'ensemble incluant AES, ChaCha20, modes d'opération.
- TLS expliqué simplement - TLS 1.3 utilise AEAD GCM ou ChaCha20-Poly1305 obligatoirement.
- Qu'est-ce que la cryptographie - panorama de la discipline.
- Chiffrement asymétrique expliqué - complément asymétrique pour échange de clé en TLS.





