<?xml version="1.0" encoding="utf-8"?>
<rfcdesc title="Post-Quantum Cryptography in OpenPGP" num="9980"
	 status="standards" wg="openpgp">
  <authors><author>S. Kousidis
  (BSI)</author><author>J. Roth</author><author>F. Strenzke (MTG
  AG)</author><author>A. Wussler (Proton AG)</author></authors>
  <rfcdate><month>June</month><year>2026</year></rfcdate>
  <date>2026-07-01</date>
<content>
  <p>Vous le savez, le jour où des CRQC (<foreign>Cryptographically
  Relevant Quantum Computer</foreign>, un <wikipedia name="Ordinateur quantique">calculateur
  quantique</wikipedia> capable de calculs non triviaux, contrairement
  aux modèles d'aujourd'hui) seront disponibles, la
  <wikipedia>cryptographie</wikipedia> sera sérieusement secouée. Il
  est donc important de travailler dès maintenant sur des algorithmes
  pour l'<wikipedia name="Cryptographie
  post-quantique">après-quantique</wikipedia>, et de les intégrer dans
  les protocoles et les formats utilisés sur l'Internet. Ce <wikipedia
  name="Request for comments">RFC</wikipedia> documente l'utilisation
  des algorithmes normalisés par le <wikipedia name="National
  Institute of Standards and Technology">NIST</wikipedia> dans le
  format <wikipedia>OpenPGP</wikipedia>.</p>
  <p>Le format <wikipedia>OpenPGP</wikipedia>, utilisé par de nombreux
  logiciels de <wikipedia>cryptographie</wikipedia>, est normalisé
  dans le <rfc num="9580" local="true"/>. La liste des algorithmes de
  chiffrement n'est pas figée et de nouveaux algorithmes peuvent être
  disponibles pour ce format. C'est le cas de ceux pour la <wikipedia
  name="Cryptographie post-quantique">cryptographie
  post-quantique</wikipedia>, un sujet d'actualité. Les messages
  <wikipedia name="Chiffrement">chiffrés</wikipedia> et/ou <wikipedia
  name="Signature numérique">signés</wikipedia> au format OpenPGP
  peuvent avoir besoin de résister à la décryption et/ou à
  l'usurpation pendant de nombreuses années. Aujourd'hui, ces messages
  utilisent typiquement <wikipedia name="Rivest Shamir
  Adleman">RSA</wikipedia> ou des algorithmes <wikipedia name="Cryptographie sur les courbes elliptiques">à courbes
  elliptiques</wikipedia>, tous étant vulnérables aux
  <wikipedia name="Ordinateur quantique">calculateurs quantiques</wikipedia>. C'est notamment en
  raison de cette nécessité de sécurité sur une longue période qu'il
  ne faut pas attendre que les CRQC soient disponibles pour intégrer
  les algorithmes post-quantiques à OpenPGP. Il y a peut-être des
  attaquants qui stockent aujourd'hui des messages OpenPGP, en
  attendant d'avoir un CRQC pour les lire (ou pour imiter des
  signatures).</p>
  <p>(Rappelons au passage qu'OpenPGP n'est pas utilisé que dans le
  <wikipedia name="Courrier électronique">courrier
  électronique</wikipedia>. Il sert, par exemple, à authentifier le
  code avec <wikipedia>git</wikipedia>, ou les
  <wikipedia name="Paquet (logiciel)">paquetages</wikipedia> compilés, avec
  <wikipedia name="Advanced Packaging Tool">apt</wikipedia> et
  <wikipedia name="RPM Package Manager">rpm</wikipedia>.)</p>
  <p>Il ne suffit pas d'ajouter les nouveaux algorithmes aux <link
  url="https://www.iana.org/assignments/openpgp/openpgp.xml#openpgp-public-key-algorithms">registres</link>
  <wikipedia name="Internet Assigned Numbers
  Authority">IANA</wikipedia>. Il y a des problèmes spécifiques, comme
  les clés hybrides (une PQ et une classique) et composées (hybrides,
  mais présentées d'une manière unifiée). En effet, il ne servirait à
  rien de déployer des algorithmes post-quantiques si ceux-ci étaient
  cassables par de la <wikipedia>cryptanalyse</wikipedia>
  classique. Rien ne dit que ces « nouveaux » algorithmes soient
  incassables. Et comme ils sont relativement récents, on ne peut pas
  avoir le même degré de confiance qu'avec <wikipedia name="Rivest
  Shamir Adleman">RSA</wikipedia> ou <wikipedia name="Elliptic curve
  digital signature algorithm">ECDSA</wikipedia>. L'approche la plus
  courante aujourd'hui, et que ce RFC suit, est d'utiliser une
  technique hybride : combinaison d'un algorithme traditionnel et d'un
  algorithme post-quantique. On n'abandonne donc pas RSA ou ECDSA, on
  les flanque d'un collègue, ce qu'on appelle le PQ/T
  (post-quantique/traditionnel, cf. section 1.1.1).</p>
  <p>Plus précisément, notre RFC utilise des
  <emphasis>composés</emphasis>, des hybrides PQ/T mais où les deux
  clés, la post-quantique et la traditionnelle, sont gérées comme une
  seule. Le <rfc num="9794" local="true"/> est la bonne lecture, si
  vous voulez approfondir ces notions d'hybride et de composé et vous
  avez aussi intérêt à lire le <rfc num="9958" local="true"/>,
  « <foreign>Post-Quantum Cryptography for Engineers</foreign> ».</p>
  <p>Quels sont ces nouveaux algorithmes ? La section 1.2 les
  résume :
  <enum>
    <item><wikipedia xml:lang="en" name="Kyber">ML-KEM</wikipedia>,
    normalisé dans la norme <link
    url="https://csrc.nist.gov/pubs/fips/203/final">FIPS-203</link>,
    pour l'<link local="echange-cles">échange de clés</link> préalable au chiffrement,</item>
    <item><wikipedia xml:lang="en" name="Lattice-based cryptography"
    anchor="CRYSTALS-Dilithium">ML-DSA</wikipedia>, normalisé dans
    <link
    url="https://csrc.nist.gov/pubs/fips/204/final">FIPS-204</link>,
    pour la signature,</item>
    <item><wikipedia xml:lang="en"
    name="SPHINCS+">SLH-DSA</wikipedia>, normalisé dans <link
    url="https://csrc.nist.gov/pubs/fips/205/final">FIPS-205</link>,
    également pour la signature.</item>
  </enum>
  Notez que l'algorithme SLH-DSA, lui, est considéré suffisamment sûr
  pour se passer de l'assistance d'un algorithme traditionnel (il
  utilise des problèmes mathématiques complètement différents de ceux
  utilisés par ML-KEM ou ML-DSA). Les deux autres vont être utilisés
  par OpenPGP avec de la cryptographie traditionnelle, en l'occurrence
  <wikipedia name="Échange de clés Diffie-Hellman basé sur les courbes elliptiques">ECDH</wikipedia> avec les courbes X25519 et X448 (<rfc
  num="7748" local="true"/>) et <wikipedia>EdDSA</wikipedia> (<rfc
  num="8032" local="true"/>). Pour la vérification d'une signature,
  les deux (post-quantique et traditionnelle) signatures doivent être
  valides (cf. sections 3 et 5.2.3). Pour le chiffrement, les deux
  clés obtenues doivent être utilisées.</p>
  <p>Le format OpenPGP permet d'avoir plusieurs signatures dans un
  message<!-- Une façon un peu tordue de le faire avec GnuPG :
  https://lists.gnupg.org/pipermail/gnupg-users/2013-July/047118.html
  Sinon, le <rfc num="9580" local="true"/> ne dit pas explicitement
  que c'est possible (il faut le déduire du format et ne dit pas
  clairement comment se fait la vérification) --> mais ces signatures
  parallèles sont différentes des clés composées utilisées pour le
  PQ/T car le succès d'une seule signature suffit à la
  validation. (Idem pour le chiffrement, cf. section 3.) Évidemment,
  le système n'est résistant aux CRQC que si toutes les signatures
  utilisent un algorithme PQ ou PQ/T. Si ces signatures multiples,
  incluant au moins une clé T (traditionnelle, sans post-quantique)
  sont moins sûres, elles ont par contre l'avantage d'assurer la
  compatibilité avec les vieilles versions des logiciels OpenPGP
  (section 5.2.5 du <rfc num="9580" local="true"/>).</p>
  <p>La section 2 du RFC donne la liste exhaustive des algorithmes qui
  viennent d'être officiellement ajoutés. À partir des trois cités
  plus haut, il y a quelques variantes, fondées sur la taille de
  certains paramètres ou sur la courbe elliptique utilisée dans le
  composé. Ainsi, SLH-DSA a trois variantes, SLH-DSA-SHAKE-128f (f
  pour <foreign>fast</foreign> car il optimise la vitesse),
  SLH-DSA-SHAKE-128s (s pour <foreign>short</foreign> car il optimise
  la taille) et SLH-DSA-SHAKE-256s. ML-KEM a deux variantes,
  ML-KEM-768+X25519 et ML-KEM-1024+X448, avec des courbes
  différentes.</p>
  <p>Notez enfin que les clés PQ/T ne doivent être utilisées qu'avec
  des données OpenPGP des versions 4 ou 6 (et même uniquement version
  6 pour ML-KEM-1024+X448 et ML-DSA). Ici, par exemple, <wikipedia
  name="GNU Privacy Guard">GnuPG</wikipedia> montre un paquet OpenPGP
  de version 3, trop vieux pour gérer le post-quantique :
  <code>
% gpg --list-packets review.txt.gpg
…
:pubkey enc packet: version 3, algo 1, keyid XXXXXXXXX
	data: [4096 bits]
  </code>
  </p>
  <p>Les sections 4, 5 et 6 du RFC expliquent en détail le format des
  nouvelles clés et comment les utiliser. La section 7 donne des
  conseils sur les algorithmes de cryptographie symétrique, par
  exemple qu'il est nécessaire de mettre en œuvre
  <wikipedia name="Advanced Encryption Standard">AES-256</wikipedia> (la version à 128 bits est
  possiblement cassable grâce à l'<wikipedia name="Algorithme de Grover">algorithme de
  Grover</wikipedia>).</p>
  <p>Et la migration depuis les anciens algorithmes ? Tous les
  logiciels qui mettent en œuvre OpenPGP ne vont pas passer au
  post-quantique en même temps. On aura des messages qui vont passer
  d'un logiciel récent à un ancien, qui ne pourra pas les lire. La
  section 8 ajoute des conseils pour bien réussir sa migration. Déjà,
  un logiciel récent, qui pense que les récepteurs de ses messages
  seront pré-quantiques peut chiffrer ses messages avec une clé PQ (ou
  PQ/T) et une clé traditionnelle (chiffrement en parallèle, où une
  seule clé est nécessaire, et pas en série, comme c'est le cas ave
  les solutions hybrides citées plus haut, où les deux clés sont
  nécessaires). Bien sûr, s'il fait cela, le message sera déchiffrable
  par un calculateur quantique. Il faut donc choisir entre sécurité et
  interopérabilité (avec les vieux logiciels). PGP étant conçu pour
  des communications asynchrones (comme le <wikipedia name="Courrier électronique">courrier
  électronique</wikipedia>), il n'est pas possible de savoir à
  l'avance les capacités du récepteur.</p>
  <p>Le même problème se pose pour les signatures. Lors d'une
  vérification de signature, n'importe laquelle des deux signatures
  sera acceptée (là encore, on parle de signatures séparées, qui ont
  toujours existé dans OpenPGP, pas des hybrides du PQ/T). Le RFC
  permet toutefois à un vérificateur paranoïaque, ou simplement un
  vérificateur qui sait que l'émetteur a une clé PQ ou PQ/T, d'ignorer
  les signatures traditionnelles.</p>
  <p>Enfin, la section 9 du RFC discute un certain nombre de questions
  de sécurité. Par exemple, elle explique comment les signatures
  composites du PQ/T ne sont pas vulnérables aux attaques par
  suppression d'une des signatures (les métadonnées indiquent
  l'identificateur de l'algorithme hybride).</p>
  <p>Quelles sont les mises en œuvre de ces nouveaux algorithmes ?
  Malheureusement, il semble que <wikipedia name="GNU Privacy
  Guard">GnuPG</wikipedia> ne <link
  url="https://lwn.net/Articles/1053089/">suive pas les récents RFC
  sur le format OpenPGP</link> (sur cette affaire, lire <link
  url="https://alioth-lists.debian.net/pipermail/pkg-gnupg-maint/2026-January/010450.html">le
  point de vue de Debian</link> ou <link
  url="https://wiki.archlinux.org/title/GnuPG">celui d'Arch
  Linux</link><!-- Mêmes Debian unstable et Arch Linux n'ont, au
  2026-02-09, que la 2.4, alors que le PQ est arrivé avec la 2.5 et
  pas conforme au draft. C'est pour cette raison -->), entre autre
  (mais pas uniquement) sur le post-quantique.  On va donc tester avec
  les autres (il existe <link
  url="https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html?q=pqc">une
  liste</link>).</p>
  <p>Si vous voulez écrire votre propre programme OpenPGP (ce que je
  ne conseillerai pas : la cryptographie, c'est difficile, et les
  bogues ne se voient pas forcément), l'annexe A du RFC, qui fait la
  grande majorité du RFC, est composée de <wikipedia name="Vecteur de test">vecteurs de
  test</wikipedia>.</p>
  <p>Les programmes testés sont conformes au
  projet de standard <link
  url="https://www.openpgp.org/about/sop/">SOP</link> et ont donc à
  peu près la même interface utilisateur (actuellement en projet, dans
  <computer><link
  url="https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/">draft-dkg-openpgp-stateless-cli</link></computer><!--
  Cf. pgp-cli-sop-NOT-YET.rfc_xml -->). Souvent, le post-quantique
  n'est pas encore intégré dans les versions officielles et il va
  falloir changer de <wikipedia name="Branche (gestion de configuration)">branche</wikipedia> et compiler.</p>
  <p>Commençons avec <link
  url="https://docs.rs/pgp/latest/pgp/">rsop</link>, écrit en
  <wikipedia name="Rust (langage)">Rust</wikipedia>. Après le
  <computer>cargo install pgp</computer> :
<code>
% rsop list-profiles  generate-key
default: v4 key using Curve25519 (alias: draft-koch-eddsa-for-openpgp-00)
compatibility: v4 key using RSA (alias: rfc4880)
performance: v6 key using Ed25519/X25519 (alias: rfc9580)
security: v6 key using Ed448/X448 (alias: rfc9580-curve448)
</code>
  Je vous l'avais bien dit : pas de post-quantique. Mais la <wikipedia
  name="Foire aux questions">FAQ</wikipedia> dans le code nous le dit
  « <foreign>### Is rPGP adding support for Post Quantum Cryptography
  (PQC)? Yes, rPGP implements the IETF draft [Post-Quantum
  Cryptography in
  OpenPGP](https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/),
  gated behind the feature `draft-pqc`.</foreign> ». Ah, c'est planqué
  dans une <foreign>feature</foreign>. Compilons :
<code>
% cargo install --features draft-pqc rsop

% rsop list-profiles  generate-key
default: v4 key using Curve25519 (alias: draft-koch-eddsa-for-openpgp-00)
compatibility: v4 key using RSA (alias: rfc4880)
performance: v6 key using Ed25519/X25519 (alias: rfc9580)
security: v6 key using Ed448/X448 (alias: rfc9580-curve448)
draft-ietf-openpgp-pqc-14-v4-ed25519-mlkem768x25519: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-ed25519-mlkem768x25519: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-mldsa65ed25519-mlkem768x25519: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-mldsa87ed448-mlkem1024x448: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-slhdsashake128s-mlkem768x25519: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-slhdsashake128f-mlkem768x25519: TESTING ONLY
draft-ietf-openpgp-pqc-14-v6-slhdsashake256s-mlkem1024x448: TESTING ONLY
</code>
  Ça marche, on a du post-quantique, utilisons-le :
  <code>
% rsop generate-key --profile draft-ietf-openpgp-pqc-14-v6-ed25519-mlkem768x25519 > key.asc
  </code>
  OK, on a une clé hybride (ML-KEM et Ed25519). Créeons la clé
  publique :
  <code>
% cat key.asc | rsop extract-cert  > cert.asc
  </code>
  Et maintenant, on peut chiffrer un fichier avec la clé publique :
  <code>
% cat hello.txt | rsop  encrypt cert.asc > hello.asc
  </code>
  Et le déchiffrer avec la clé privée :
<code>
% cat hello.asc | rsop decrypt key.asc 
Hello, world
</code>
  Bon, on a tout fait avec le même programme, mais le but d'OpenPGP
  est l'interopérabilité. Essayons avec un deuxième programme,
  Sequoia, pour lequel il y a <link
  url="https://sequoia-pgp.org/blog/2025/11/15/202511-post-quantum-cryptography/">des
  instructions détaillées pour le compiler avec gestion du
  post-quantique</link> :
  <code>
% sudo apt install libsqlite3-dev
% git clone https://gitlab.com/sequoia-pgp/sequoia-sq.git
% git checkout pqc
% cargo build --release --locked --no-default-features --features crypto-openssl
  </code>
  Et utilisons-le pour regarder les fichiers produits par rsop :
  <code>
% sq  inspect key.asc 
key.asc: Transferable Secret Key.

      Fingerprint: AC7FD6CBD09E90C928C2ED5796A69001B5F0535CE6BF09C227DFE71063006BD0
  Public-key algo: Ed25519
  Public-key size: 256 bits
       Secret key: Unencrypted
    Creation time: 2026-02-09 17:36:25 UTC
        Key flags: certification, signing

           Subkey: 91BED065B7E654656D3354CA16E901D8F8B192874385EB6C325421055AFB5B9E
  Public-key algo: ML-KEM-768+X25519
       Secret key: Unencrypted
    Creation time: 2026-02-09 17:36:25 UTC
        Key flags: transport encryption, data-at-rest encryption
  </code>
  Joli, non ? rsop avait bien fabriqué une clé hybride et sq arrive à
  la lire.
<code>  
% cat hello.asc | sq  decrypt --recipient-file key.asc
Encrypted and protected using AES-256/OCB
Hello, world
Decrypted by AC7FD6CBD09E90C928C2ED5796A69001B5F0535CE6BF09C227DFE71063006BD0, unknown
0 authenticated signatures.
</code>
Et Sequoia peut déchiffrer les messages chiffrés par rsop.
<code>
% sq inspect --cert-file cert.asc &lt; hello.asc
OpenPGP Certificate.

      Fingerprint: AC7FD6CBD09E90C928C2ED5796A69001B5F0535CE6BF09C227DFE71063006BD0
  Public-key algo: Ed25519
  Public-key size: 256 bits
    Creation time: 2026-02-09 17:36:25 UTC
        Key flags: certification, signing

           Subkey: 91BED065B7E654656D3354CA16E901D8F8B192874385EB6C325421055AFB5B9E
  Public-key algo: ML-KEM-768+X25519
    Creation time: 2026-02-09 17:36:25 UTC
        Key flags: transport encryption, data-at-rest encryption
</code>
  Et examiner ses clés. rsop et sq étaient tous les deux écrits en
  <wikipedia name="Rust (langage)">Rust</wikipedia> donc testons
  l'interopérabilité avec un programme en <wikipedia name="Go
  (langage)">Go</wikipedia> :
<code>
% git clone https://github.com/ProtonMail/gosop.git
% cd gosop 
% git checkout gosop-gopenpgp-v3-pqc
% go build

% ./gosop list-profiles generate-key
default: Generate v4 keys using Curve25519
compatibility: Generate v4 keys using 3072-bit RSA (alias: rfc4880)
performance: Generate v6 keys using Ed25519/X25519 (alias: rfc9580)
security: Generate v6 keys using Ed448/X448
draft-ietf-openpgp-pqc-09: ML-KEM-768 and ML-DSA-65
draft-ietf-openpgp-pqc-09-high-security: ML-KEM-1024 and ML-DSA-87
draft-ietf-openpgp-persistent-symmetric-keys-00: AEAD and HMAC

% ./gosop/gosop decrypt key.asc &lt; hello.asc
Hello, world
</code>
  Et tout se passe bien.
  </p>
<!-- Also, for signatures, if you want a composite, consider aligning on Composite Signatures  (I am happy to help you with that), from LAMPS for the hybrid combinations you need.   Just specify the code points that point to the Composite combinations you need. Then you get all the non-separability and security properties we have worked on within LAMPS for the past 3 years.
(Falko Strenzke)

OpenPGP signatures, as opposed to CMS, include meta data, among which
is the algID. This means domain separation between the standalone and
composite is given already. -->
</content>
</rfcdesc>
