Aller au contenu
ecdsa.com

age vs GPG : chiffrer des fichiers et des secrets en 2026

age ne fait qu’une chose : chiffrer des fichiers pour de courtes clés publiques ou avec une phrase de passe. GnuPG implémente l’intégralité d’OpenPGP, y compris les signatures, la gestion des clés et l’e-mail, avec la complexité que cela implique.

Choisir entre age et GPG, c’est choisir entre un petit outil de chiffrement spécialisé et une implémentation complète d’OpenPGP. age (format age-encryption.org/v1, spécifié dans C2SP) chiffre un fichier pour un ou plusieurs destinataires, chacun étant une courte chaîne comme age1…, une clé publique SSH ou une clé post-quantique age1pq1…, à l’aide d’une encapsulation de clé X25519 ou ML-KEM hybride, et de ChaCha20-Poly1305 pour la charge utile. GnuPG implémente OpenPGP : chiffrement, signatures, certification, trousseaux de clés, serveurs de clés, cartes à puce et intégration à la messagerie, avec des décennies de compatibilité derrière lui.

Vue d’ensemble

ageGnuPG (OpenPGP)
PérimètreChiffrement de fichiers uniquementChiffrement, signature, certification, gestion des clés
Spécificationage v1 (C2SP), un seul format, aucune version à négocierRFC 9580 (2024) et RFC 9980 (2026) ; GnuPG suit LibrePGP
Clé publique62 caractères (age1…) ; 1959 caractères en post-quantique (age1pq1…)Clé binaire avec ID utilisateur et autosignatures ; 473 octets pour Ed25519 plus Cv25519 (mesuré)
AlgorithmesX25519, hybride ML-KEM-768 + X25519, scrypt pour les phrases de passe, ChaCha20-Poly1305, HKDF et HMAC-SHA-256Nombreux : RSA, ECC, AES, Camellia, algorithmes de chiffrement historiques pour les anciennes données ; ML-KEM-768 + X25519 dans GnuPG 2.5
ConfigurationAucunePréférences, modèles de confiance, paramètres d’algorithmes et de compression
Texte chiffré mesuré pour un fichier de 26 octets226 octets (X25519) ; 1685 octets (post-quantique)203 octets (Cv25519) ; 1288 octets (sous-clé ML-KEM-768 + X25519)
Clés SSH comme destinatairesOui (ssh-ed25519, ssh-rsa)Non
Clés matériellesPlugins : YubiKey PIV, TPM, Secure EnclaveCartes à puce OpenPGP et clés de sécurité
SignaturesAucune, par conceptionOui
Découverte des clésAucune ; les destinataires s’échangent directementServeurs de clés, WKD, trousseaux
Fichiers volumineuxTraitement en flux, par segments authentifiés de 64 Kio ; API de déchiffrement avec accès aléatoire depuis la 1.3Traitement en flux ; un seul paquet AEAD découpé en segments

Chiffrer le même fichier des deux façons

Le script ci-dessous chiffre un secret de 26 octets pour un destinataire age X25519, un destinataire age post-quantique, une sous-clé GnuPG Cv25519 et une sous-clé GnuPG ML-KEM-768 + X25519, déchiffre chaque fichier et compare les tailles (age 1.3.2, GnuPG 2.5.21). Tout se passe dans un répertoire temporaire.

age et GnuPG, classique et post-quantique
#!/bin/sh
dir=$(mktemp -d /tmp/agegpg.XXXXXX)   # short path: gpg-agent sockets need one
cd "$dir" || exit 1
export GNUPGHOME="$dir/g"
mkdir -m 700 g
printf 'db_password=correct-horse\n' > secret.env    # 26 bytes

echo "== age"
age-keygen -o key.txt 2> /dev/null
recipient=$(age-keygen -y key.txt)
echo "recipient: ${#recipient} characters"
age -r "$recipient" -o secret.env.age secret.env
age -d -i key.txt secret.env.age | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.age | tr -d ' ') bytes"

echo "== age, post-quantum recipient"
age-keygen -pq -o pq.txt 2> /dev/null
pqrecipient=$(age-keygen -y pq.txt)
echo "recipient: ${#pqrecipient} characters"
age -r "$pqrecipient" -o secret.env.pq.age secret.env
age -d -i pq.txt secret.env.pq.age | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.pq.age | tr -d ' ') bytes"

echo "== GnuPG"
gpg --batch --quiet --passphrase '' --quick-gen-key "Ops <ops@example.org>" ed25519 cert 1y
fpr=$(gpg --list-keys --with-colons ops@example.org 2> /dev/null | awk -F: '/^fpr/ { print $10; exit }')
gpg --batch --quiet --passphrase '' --quick-add-key "$fpr" cv25519 encr 1y
gpg --batch --quiet --trust-model always -r ops@example.org -o secret.env.gpg -e secret.env
gpg --batch --quiet -d secret.env.gpg 2> /dev/null | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.gpg | tr -d ' ') bytes"
echo "public key export: $(gpg --export ops@example.org | wc -c | tr -d ' ') bytes binary"

echo "== GnuPG, ML-KEM-768 + X25519 subkey"
gpg --batch --quiet --passphrase '' --quick-gen-key "Ops PQ <ops-pq@example.org>" ed25519 cert 1y
fpr=$(gpg --list-keys --with-colons ops-pq@example.org 2> /dev/null | awk -F: '/^fpr/ { print $10; exit }')
gpg --batch --quiet --passphrase '' --quick-add-key "$fpr" ky768_cv25519 encr 1y
gpg --batch --quiet --trust-model always -r ops-pq@example.org -o secret.env.pq.gpg -e secret.env
gpg --batch --quiet -d secret.env.pq.gpg 2> /dev/null | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.pq.gpg | tr -d ' ') bytes"
gpgconf --kill gpg-agent
cd / && rm -rf "$dir"
Sortie
== age
recipient: 62 characters
decrypted: identical
ciphertext: 226 bytes
== age, post-quantum recipient
recipient: 1959 characters
decrypted: identical
ciphertext: 1685 bytes
== GnuPG
decrypted: identical
ciphertext: 203 bytes
public key export: 473 bytes binary
== GnuPG, ML-KEM-768 + X25519 subkey
decrypted: identical
ciphertext: 1288 bytes

Les deux ajoutent un en-tête fixe par destinataire et un léger surcoût d’authentification : pour des fichiers réels, la différence est donc négligeable. Le surcoût post-quantique correspond au texte chiffré ML-KEM-768 (1088 octets) transporté dans chaque bloc de destinataire (stanza) ; celui d’age est plus important surtout parce que son en-tête est textuel, avec les valeurs binaires en base64. Le script n’utilise --trust-model always que parce que la clé a été créée une seconde plus tôt ; en usage réel, vous vérifieriez l’empreinte du destinataire.

Les détails d’interopérabilité qui comptent

Sur les fichiers ci-dessus, la commande gpg --list-packets montre deux choses bonnes à savoir. Pour sa clé Cv25519, GnuPG 2.5 a écrit un paquet OCB « AEAD encrypted packet », le format LibrePGP, plutôt que le paquet de données chiffrées version 2 que définit la RFC 9580, parce que les propres clés de GnuPG annoncent sa prise en charge ; les implémentations qui suivent uniquement la RFC 9580 peuvent être incapables de lire de tels fichiers. Pour la sous-clé post-quantique, GnuPG a utilisé l’algorithme à clé publique 8, son composite Kyber LibrePGP, alors que la RFC 9980 attribue le numéro 35 à ML-KEM-768 + X25519 : les clés post-quantiques de GnuPG et les clés RFC 9980 ne sont donc pas interopérables. age n’a qu’un seul format et une seule construction post-quantique (HPKE avec l’hybride ML-KEM-768 et X25519, également appelé X-Wing), avec des vecteurs de test publiés.

Pourquoi age est volontairement petit

age laisse de côté tout ce qui rendait OpenPGP difficile à utiliser en toute sécurité : pas de négociation d’algorithme, pas de compression (qui peut laisser fuir des informations sur le texte clair), pas de mode non authentifié, pas de serveur de clés ni de toile de confiance. Un destinataire est une chaîne que vous pouvez coller dans un fichier de configuration, et un fichier chiffré pour plusieurs destinataires comporte un bloc (stanza) par destinataire. Le prix à payer, c’est le périmètre : age ne sait pas signer, il ne prouve donc pas qui a chiffré un fichier, et il ne gère ni ne distribue les clés. Des outils comblent ces lacunes autour de lui : SOPS chiffre des valeurs YAML et JSON pour des destinataires age, et des plugins permettent de conserver les identités (clés privées) sur des YubiKey, des TPM ou dans la Secure Enclave de macOS.

L’étendue de GnuPG fait sa valeur là où OpenPGP est le langage commun : e-mails signés et chiffrés avec des correspondants existants, dépôts de paquets, signatures de versions publiées que les vérificateurs en aval contrôlent déjà, et cartes à puce OpenPGP qui réunissent les clés de signature, de chiffrement et d’authentification.

Quand choisir l’un ou l’autre

  • Secrets dans Git (SOPS), variables CI, sauvegardes, dotfiles : age, avec un destinataire par personne ou par machine, et un destinataire de récupération matériel ou hors ligne.
  • Chiffrer pour quelqu’un dont vous avez déjà la clé SSH : age.
  • Archives confidentielles à long terme : age avec des destinataires post-quantiques age1pq1, pour résister aux attaques de type récolter maintenant, déchiffrer plus tard.
  • E-mail chiffré : OpenPGP (ou S/MIME, voir S/MIME vs OpenPGP).
  • Chiffrer et signer en une seule étape pour un destinataire qui utilise OpenPGP : GnuPG.
  • Signatures de versions et de paquets : ni l’un ni l’autre en tant qu’outil de chiffrement ; voir Sigstore vs GPG.

Notes de migration

  1. Générez des identités age (clés privées) par personne ou par machine (age-keygen, ou age-keygen -pq dès que toutes les personnes qui chiffrent ou déchiffrent utilisent age 1.3 ou une version ultérieure), et conservez une identité de récupération hors ligne.
  2. Rechiffrez plutôt que de convertir : déchiffrez chaque fichier GPG avec l’ancienne clé et chiffrez-le pour les nouveaux destinataires ; il n’existe aucune conversion de format. Pour SOPS, ajoutez les destinataires age aux règles de création dans .sops.yaml et exécutez sops updatekeys sur chaque fichier ; lorsque vous retirerez plus tard les clés PGP, enchaînez avec sops rotate pour que la clé de données change elle aussi.
  3. Conservez la clé GPG jusqu’à ce que chaque ancien fichier et chaque sauvegarde aient été rechiffrés ou soient arrivés à expiration.
  4. Remplacez les signatures GPG séparément par des signatures SSH, minisign ou Sigstore, puisque age n’en fournit aucune.
  5. Vérifiez les tailles et les outils avec l’outil de chiffrement age et examinez les anciens fichiers avec l’inspecteur OpenPGP pour savoir quelles clés et quels algorithmes ils utilisent.

Références

Tous les comparatifs