Aller au contenu
ecdsa.com

AES-GCM vs ChaCha20-Poly1305 : quel AEAD choisir

Ce sont deux AEAD normalisés, avec un tag de 128 bits et des nonces de 96 bits. AES-GCM l’emporte sur les processeurs dotés d’instructions AES et dans les environnements FIPS ; ChaCha20-Poly1305 l’emporte partout ailleurs.
Éléments comparésAES-GCMChaCha20-Poly1305

Choisir entre AES-GCM et ChaCha20-Poly1305, c’est choisir entre les deux algorithmes de chiffrement authentifié qui transportent la quasi-totalité du trafic chiffré : TLS 1.3, QUIC, SSH, WireGuard, age et la plupart des chiffrements applicatifs. Tous deux sont sûrs lorsqu’ils sont correctement utilisés, tous deux s’effondrent dès qu’un nonce se répète, et leur vitesse dépend fortement du matériel.

Vue d’ensemble

AES-GCMChaCha20-Poly1305
SpécificationNIST SP 800-38D (2007)RFC 8439 (2018, remplace la RFC 7539)
Tailles de clé128, 192, 256 bits256 bits
Nonce96 bits recommandés96 bits (192 bits dans XChaCha20)
Tag128 bits (plus court autorisé, mais déconseillé)128 bits
Données max. par messageenviron 64 Gio (2³² − 2 blocs)256 Gio (2³² blocs de 64 octets)
Budget de nonces aléatoires par clé2³² messages (SP 800-38D)Même ordre de grandeur avec des nonces de 96 bits ; pratiquement illimité avec XChaCha20
Réutilisation de nonceRévèle le XOR des textes clairs et la clé GHASH, ce qui permet des falsificationsRévèle le XOR des textes clairs et permet des falsifications
Débit, 16 Kio, OpenSSL 3.6.510,4 Go/s (AES-128), 8,8 Go/s (AES-256)2,1 Go/s
Débit, messages de 16 octets0,14 Go/s (AES-256)0,52 Go/s
Temps constant sans support matérielDifficile (l’AES à base de tables présente des fuites via les caches)Naturel (addition, rotation, XOR)
Approuvé FIPS 140-3OuiNon
TLS 1.3TLS_AES_128_GCM_SHA256 (obligatoire), TLS_AES_256_GCM_SHA384 (recommandée)TLS_CHACHA20_POLY1305_SHA256 (recommandée)
Autres usagesJWE A128GCM et A256GCM, IPsec, SSH aes256-gcm@openssh.com, chiffrement de disques et dans le cloudWireGuard, SSH chacha20-poly1305@openssh.com, age, libsodium

Débit mesuré avec openssl speed -evp sur un cœur d’un Apple M4 Max, qui dispose d’instructions AES et de multiplication polynomiale.

Les performances dépendent du processeur

AES-GCM est conçu pour le matériel : chaque tour AES s’exécute en une seule instruction (AES-NI sur x86, extensions cryptographiques ARMv8) et GHASH utilise la multiplication sans retenue. Avec ces deux jeux d’instructions, il atteint ici environ 10 Go/s par cœur, soit environ cinq fois le débit de ChaCha20-Poly1305. Sans eux, AES doit recourir soit à des tables de correspondance, lentes et qui laissent fuir des bits de clé par les temps d’accès au cache, soit à du code en bitslicing, en temps constant mais lent. ChaCha20 n’a besoin que d’additions sur 32 bits, de rotations et de XOR : il s’exécute donc rapidement et en temps constant sur n’importe quel processeur, y compris les téléphones d’entrée de gamme et les microcontrôleurs.

Avec de petits messages, l’écart se réduit, voire s’inverse : avec des entrées de 16 octets, ChaCha20-Poly1305 a atteint 0,52 Go/s contre 0,14 Go/s pour AES-256-GCM, car le coût d’initialisation de GCM domine. Pour des enregistrements TLS typiques (jusqu’à 16 Kio) sur des serveurs, AES-GCM est plus rapide ; pour de nombreux paquets minuscules, la différence reste faible dans un sens comme dans l’autre.

Nonces et limites

Tous deux sont des algorithmes de chiffrement en mode compteur associés à des authentificateurs à usage unique : la paire (clé, nonce) ne doit donc jamais se répéter. Une répétition révèle le XOR des deux textes clairs ; avec GCM, elle permet en outre à un attaquant de récupérer la sous-clé d’authentification et de forger des messages sous cette clé, et avec Poly1305, elle expose la clé à usage unique et permet une falsification pour ce nonce. NIST SP 800-38D limite les IV de 96 bits générés aléatoirement à 2³² invocations par clé pour que la probabilité de collision reste négligeable ; TLS contourne le problème en dérivant les nonces des numéros de séquence des enregistrements et en renouvelant les clés.

Si votre système génère des nonces aléatoires pour de nombreux messages sous une même clé, utilisez une construction qui offre un espace de nonces plus grand ou qui résiste à la mauvaise utilisation des nonces :

  • XChaCha20-Poly1305 (nonces de 192 bits, décrit dans un Internet-Draft de l’IRTF et implémenté notamment par libsodium), avec lequel les nonces aléatoires sont sûrs pour un nombre pratiquement illimité de messages ;
  • AES-GCM-SIV (RFC 8452), avec lequel une réutilisation de nonce révèle seulement si deux messages étaient identiques ;
  • ou une dérivation de clé par message ou par session, comme le font TLS, age et HPKE.

Aucun des deux algorithmes ne s’engage sur sa clé : on peut fabriquer un texte chiffré qui se déchiffre valablement sous deux clés différentes, ce qui compte pour les schémas à plusieurs destinataires ou fondés sur un mot de passe (le problème des « salamandres invisibles », invisible salamanders). Ajoutez un engagement de clé (key commitment) si des attaquants peuvent choisir les clés.

Node.js 26 : la même interface AEAD pour les deux algorithmes
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";

const plaintext = Buffer.from("card ending 4242, amount 19.99");
const aad = Buffer.from("order=7781");

for (const algorithm of ["aes-256-gcm", "chacha20-poly1305"]) {
  const key = randomBytes(32);
  const nonce = randomBytes(12); // 96-bit nonce for both; never reuse with the same key
  const cipher = createCipheriv(algorithm, key, nonce, { authTagLength: 16 });
  cipher.setAAD(aad);
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
  const tag = cipher.getAuthTag();

  const decipher = createDecipheriv(algorithm, key, nonce, { authTagLength: 16 });
  decipher.setAAD(aad);
  decipher.setAuthTag(tag);
  const roundTrip = Buffer.concat([decipher.update(ciphertext), decipher.final()]);

  console.log(algorithm.padEnd(18), "ciphertext", ciphertext.length, "bytes + tag", tag.length, "bytes, decrypts:", roundTrip.equals(plaintext));
}
Sortie
aes-256-gcm        ciphertext 30 bytes + tag 16 bytes, decrypts: true
chacha20-poly1305  ciphertext 30 bytes + tag 16 bytes, decrypts: true

Comment TLS choisit entre les deux

TLS 1.3 impose à toute implémentation de prendre en charge TLS_AES_128_GCM_SHA256 et recommande AES-256-GCM et ChaCha20-Poly1305. Les clients dépourvus d’accélération matérielle AES placent ChaCha20 en tête de leur liste ; les serveurs qui respectent cette préférence servent à chaque client l’algorithme de chiffrement le plus rapide. OpenSSL met cela en œuvre avec l’option PrioritizeChaCha (SSL_OP_PRIORITIZE_CHACHA), qui ne privilégie ChaCha20 que lorsque le client l’a placé en premier, et BoringSSL utilise des groupes de préférence égale dans le même but. Le générateur de configurations TLS produit des paramètres de serveur qui conservent les deux suites.

Quand choisir l’un ou l’autre

  • Serveurs TLS et QUIC : activez les deux ; privilégiez AES-GCM, mais laissez les clients qui placent ChaCha20 en premier l’obtenir.
  • Environnements FIPS 140-3 : AES-GCM ; ChaCha20-Poly1305 n’est pas un algorithme approuvé.
  • Terminaux mobiles, IoT et microcontrôleurs sans accélération AES : ChaCha20-Poly1305.
  • Chiffrement applicatif avec des nonces aléatoires et des clés de longue durée : XChaCha20-Poly1305 ou AES-GCM-SIV.
  • JWE : A256GCM (ou A128GCM) ; ChaCha20 ne figure pas dans le registre JWA de base.
  • Messages uniques très volumineux (plus de 64 Gio) : découpez-les en segments avec un nonce par segment (comme le fait age avec des segments ChaCha20-Poly1305 de 64 Kio) ; ne vous fiez pas aux limites par message.

Notes de migration

Dans un système bien conçu, changer d’AEAD modifie le format du texte chiffré, et rien d’autre.

  1. Versionnez votre format : stockez un identifiant d’algorithme et un identifiant de clé avec chaque texte chiffré, pour que les anciennes données restent lisibles.
  2. Utilisez une clé distincte par algorithme : dérivez des clés différentes (par exemple avec HKDF et des chaînes info différentes) plutôt que de réutiliser une même clé pour les deux.
  3. Revérifiez la génération des nonces : les compteurs doivent être persistés d’un redémarrage à l’autre ; les nonces aléatoires doivent rester dans les limites indiquées plus haut, sinon passez à XChaCha20.
  4. Rechiffrez au fil de l’eau : déchiffrez avec l’ancien algorithme et réécrivez avec le nouveau à mesure que les enregistrements sont manipulés, sauf si une échéance de conformité impose une migration en masse.
  5. Mesurez sur le matériel réel : le classement en vitesse s’inverse entre les processeurs de serveur et les petits appareils.

Références

Tous les comparatifs