Cryptographie appliquée

CBC vs GCM : pourquoi GCM gagne en 2026

CBC vs GCM 2026 : différences techniques, padding oracle (BEAST, POODLE, Lucky 13), AEAD obligatoire TLS 1.3, performance AES-NI, migration legacy.

Naim Aouaichia
20 min de lecture
  • CBC
  • GCM
  • AEAD
  • AES
  • TLS
  • Padding Oracle
  • Cipher Mode
  • Cryptographie

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

ModeAnnéeDescriptionStatut 2026
ECB (Electronic Codebook)1981Chiffrement bloc par bloc indépendantInterdit (déterministe, fuites patterns)
CBC (Cipher Block Chaining)1981Chaque bloc XOR avec précédent chiffré + IVDéprécié pour nouveaux usages
CFB (Cipher Feedback)1981Stream-like via feedbackRare 2026
OFB (Output Feedback)1981Stream-like via feedbackRare 2026
CTR (Counter)1981 / utilisé 2000+Compteur chiffré → keystream XORComposant GCM
XTS (XEX with tweak and ciphertext stealing)2007Chiffrement disqueStandard chiffrement disque
GCM (Galois/Counter Mode)2007CTR + Galois MAC = AEADRecommandé 2026
CCM (Counter with CBC-MAC)2002Counter + CBC-MAC pour AEADNiche IoT (Bluetooth LE, WPA2)
OCB (Offset Codebook)2003AEAD optimisé performanceÉmergent, RFC 7253
AES-GCM-SIV2017 (RFC 8452)GCM-SIV résiste nonce reuseRecommandé 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 | ... | Cn

Chaque 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-1

Padding 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 || mac

Construction 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 :

  1. CTR mode pour chiffrement (stream cipher dérivé de AES).
  2. 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.

DimensionCBCGCM
TypeMode chiffrement seulAEAD (chiffrement + authentification)
ConfidentialitéOuiOui
IntégritéNon (MAC séparé requis)Oui (intégrée)
Authentification AADNonOui
PaddingObligatoire (PKCS#7 standard)Non (stream cipher)
IV / Nonce taille16 octets recommandé12 octets recommandé
IV / Nonce générationAléatoire imprévisibleUnique (jamais réutiliser)
Parallélisation chiffrementNon (séquentiel)Oui
Parallélisation déchiffrementOuiOui
Tag d'authentificationExterne (HMAC) typiquement 32 octetsIntégré 16 octets
Performance avec AES-NILimité par séquentialitéExcellent (5-10 GB/s)
Padding oracle vulnérableOui (si mauvaise implémentation)Non (pas de padding)
StandardisationNIST SP 800-38A (2001)NIST SP 800-38D (2007)
TLS 1.3 supportéNon (CBC supprimé)Oui (recommandé)
Statut 2026Déprécié pour nouveaux usagesRecommandé 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

ModeThroughputNotes
AES-128-ECB2-4 GB/sParallélisable, dangereux
AES-128-CBC encrypt1-2 GB/sSéquentiel chiffrement
AES-128-CBC decrypt4-8 GB/sParallélisable décryption
AES-128-CTR4-10 GB/sParallélisable
AES-128-GCM5-10 GB/sCTR + GHASH parallèles
AES-128-OCB6-12 GB/sPlus rapide que GCM, RFC 7253
AES-256-GCM4-8 GB/sLégèrement plus lent que 128
ChaCha20-Poly13052-4 GB/sPure 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 + tag

Stockage 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 + tag

Birthday 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'usageMode recommandé
TLS 1.3 (serveur web)AES-128-GCM ou ChaCha20-Poly1305
TLS 1.2 moderneAES-128-GCM-SHA256 ou ChaCha20-Poly1305-SHA256
API JWT signingEdDSA ou ES256 (pas chiffrement, mais AEAD si JWE)
Application-level encryptionlibsodium crypto_secretbox (XChaCha20-Poly1305)
Chiffrement de fichiersage (X25519 + ChaCha20-Poly1305)
Chiffrement de disqueXTS-AES (LUKS Linux, FileVault macOS, BitLocker Windows)
Wireguard VPNChaCha20-Poly1305
Backup chiffréAES-256-GCM ou ChaCha20-Poly1305
Database column encryptionAES-256-GCM ou AES-GCM-SIV (si nonces distribués)
Session cookiesAES-256-GCM dans iron-session, secure-cookie patterns
Bluetooth LEAES-128-CCM (standard imposé)
WPA3 Wi-FiAES-128-CCM (standard imposé)
Embedded contraintAES-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

Questions fréquentes

  • Faut-il encore utiliser CBC en 2026 ?
    Non, sauf compatibilité legacy stricte. CBC (Cipher Block Chaining) reste techniquement valide mais expose à de nombreuses attaques (BEAST, POODLE, Lucky 13, padding oracles génériques) qui exigent défenses additionnelles complexes (Encrypt-then-MAC, constant-time, etc.). GCM (Galois/Counter Mode) intègre nativement authentification + chiffrement (AEAD), élimine ces classes d'attaques par construction. TLS 1.3 (août 2018) impose AEAD uniquement, supprimant CBC. Pour nouveaux projets en 2026 : GCM ou ChaCha20-Poly1305 obligatoires. CBC acceptable uniquement si système legacy ne supporte pas AEAD ET avec implémentation Encrypt-then-MAC rigoureuse + protections side-channel.
  • Quelle différence concrète entre CBC et GCM ?
    CBC chaîne les blocs (chaque bloc XOR avec le précédent chiffré) avec IV initial, fournit confidentialité uniquement, exige MAC séparé pour intégrité. GCM combine compteur (CTR mode pour chiffrement) + Galois field multiplication (pour authentification) en une opération unifiée AEAD. Différences pratiques : CBC chiffrement séquentiel (lent, parallélisation impossible côté chiffrement), GCM parallèle (très rapide CPU moderne). CBC nécessite padding (vulnérable padding oracle), GCM stream cipher (pas de padding). CBC tag MAC séparé (HMAC), GCM tag intégré 16 octets. CBC IV 16 octets recommandé aléatoire, GCM IV 12 octets nonce unique obligatoire. GCM produit ciphertext + 16 octets de tag, CBC produit ciphertext padded + tag MAC séparé.
  • Pourquoi GCM est-il plus performant que CBC ?
    Trois raisons techniques. 1) CTR mode (base de GCM) est parallélisable : chaque bloc peut être chiffré indépendamment, exploitation maximale CPU multi-core. CBC est séquentiel : bloc N nécessite résultat bloc N-1, pas de parallélisation côté chiffrement. 2) AES-NI (Intel/AMD depuis 2010) accélère matériellement AES, mais CBC séquentiel limite le bénéfice. CTR/GCM exploitent pleinement AES-NI. 3) AVX (Advanced Vector Extensions) permet vectorisation GCM moderne (PCLMULQDQ pour Galois multiplication). Benchmarks 2026 sur CPU moderne avec AES-NI : AES-128-CBC environ 1-2 GB/s, AES-128-GCM environ 5-10 GB/s. Différence 5-10x en performance, négligeable sur volume mais critique en serveur TLS haute charge.
  • Quel est le risque de réutiliser un nonce GCM ?
    Catastrophique. La réutilisation d'un nonce GCM avec la même clé permet à un attaquant de récupérer le keystream (XOR des deux ciphertexts révèle XOR des plaintexts) ET de forger des messages authentifiés (récupération du clé d'authentification H). Vulnérabilité fondamentale du mode GCM : nonce-misuse-resistance NULLE. Cas réels : Apple iMessage (2016 paper Garman), tor (vulnérabilité historique), divers IoT vendors. Défenses : 1) Nonce déterministe avec compteur incrémenté monotonement (jamais réinitialiser ni partager). 2) Nonce 96 bits aléatoire si volume inférieur à 2^32 messages par clé (limite birthday paradox). 3) Pour requêtes massives ou environnements distribués, utiliser AES-GCM-SIV (RFC 8452, Adam Langley) qui résiste au nonce reuse.
  • AES-GCM-SIV remplace-t-il AES-GCM ?
    Pas universellement, mais dans les cas où nonce reuse est risqué. AES-GCM-SIV (RFC 8452, août 2019) est conçu par Adam Langley (Google) comme variante AEAD résistante à la réutilisation accidentelle de nonce. Si nonce reused, dégradation gracieuse au lieu de compromission totale. Trade-off : performance ~2x plus lente que AES-GCM standard. Cas d'usage idéal : environnements distribués où coordination de nonces est difficile (multi-master databases, edge computing avec sync intermittent), bibliothèques pour développeurs novices (limite les bugs). Adopté par Google AGE, Cloudflare, Apple. Pour TLS, GCM reste standard car TLS 1.3 protocole assure unicité de nonce. Pour application-level encryption, considérer AES-GCM-SIV ou ChaCha20-Poly1305.
  • Comment migrer de CBC vers GCM dans un système existant ?
    Stratégie en 4 étapes. 1) Inventaire : identifier tous les usages CBC (TLS configs, application-level encryption, fichiers chiffrés au repos, BDD, backups). 2) Évaluation compatibilité : vérifier que tous les clients/lecteurs supportent GCM (depuis 2010+ pour TLS, 2014+ pour bibliothèques applicatives modernes). 3) Migration progressive : nouveaux chiffrements en GCM, conservation CBC pour déchiffrement legacy. Format hybride permet de stocker à la fois ciphertext CBC ancien et nouveaux chiffrements GCM. 4) Rotation et re-encryption : migrer données chiffrées CBC en GCM via re-encryption batch (peut prendre jours/semaines pour gros volumes). Pour TLS : configuration Mozilla Modern (TLS 1.3 only) élimine CBC. Pour application-level : libsodium ou wrapped libraries qui choisissent GCM/ChaCha20-Poly1305 par défaut.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.