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
| age | GnuPG (OpenPGP) | |
|---|---|---|
| Périmètre | Chiffrement de fichiers uniquement | Chiffrement, signature, certification, gestion des clés |
| Spécification | age v1 (C2SP), un seul format, aucune version à négocier | RFC 9580 (2024) et RFC 9980 (2026) ; GnuPG suit LibrePGP |
| Clé publique | 62 caractères (age1…) ; 1959 caractères en post-quantique (age1pq1…) | Clé binaire avec ID utilisateur et autosignatures ; 473 octets pour Ed25519 plus Cv25519 (mesuré) |
| Algorithmes | X25519, hybride ML-KEM-768 + X25519, scrypt pour les phrases de passe, ChaCha20-Poly1305, HKDF et HMAC-SHA-256 | Nombreux : RSA, ECC, AES, Camellia, algorithmes de chiffrement historiques pour les anciennes données ; ML-KEM-768 + X25519 dans GnuPG 2.5 |
| Configuration | Aucune | Préférences, modèles de confiance, paramètres d’algorithmes et de compression |
| Texte chiffré mesuré pour un fichier de 26 octets | 226 octets (X25519) ; 1685 octets (post-quantique) | 203 octets (Cv25519) ; 1288 octets (sous-clé ML-KEM-768 + X25519) |
| Clés SSH comme destinataires | Oui (ssh-ed25519, ssh-rsa) | Non |
| Clés matérielles | Plugins : YubiKey PIV, TPM, Secure Enclave | Cartes à puce OpenPGP et clés de sécurité |
| Signatures | Aucune, par conception | Oui |
| Découverte des clés | Aucune ; les destinataires s’échangent directement | Serveurs de clés, WKD, trousseaux |
| Fichiers volumineux | Traitement en flux, par segments authentifiés de 64 Kio ; API de déchiffrement avec accès aléatoire depuis la 1.3 | Traitement 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.
#!/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"
== 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
- Générez des identités age (clés privées) par personne ou par machine (
age-keygen, ouage-keygen -pqdè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. - 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.yamlet exécutezsops updatekeyssur chaque fichier ; lorsque vous retirerez plus tard les clés PGP, enchaînez avecsops rotatepour que la clé de données change elle aussi. - Conservez la clé GPG jusqu’à ce que chaque ancien fichier et chaque sauvegarde aient été rechiffrés ou soient arrivés à expiration.
- Remplacez les signatures GPG séparément par des signatures SSH, minisign ou Sigstore, puisque age n’en fournit aucune.
- 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.