简短回答:IETF 在 RFC 9580(2024年7月)中修订了 OpenPGP:引入使用 SHA-256 指纹的 v6 密钥,把 Ed25519 和 X25519 定为必须实现的算法,并加入加盐签名、Argon2 和认证加密。后量子算法随后在 RFC 9980(2026年)中跟进,主要面向 v6 密钥。GnuPG 没有采用 RFC 9580,而是遵循 LibrePGP——这是它自己延续下来的规范,使用 v5 密钥和自己的 Kyber 加密;它对 RFC 9980 只提供部分支持,且需用 --allow-9980 启用。Sequoia 实现了 RFC 9580 和 RFC 9980,但默认仍创建 v4 密钥。实际做法是:对于别人必须用手头现有工具来验证的密钥(Git 托管平台、包管理器、发布页面),目前应使用 v4 Ed25519/Cv25519 密钥;它在我们测试过的所有环境中都能正常使用。只有在每个验证方都运行 Sequoia 或其他 RFC 9580 实现的生态中,才使用 v6 或后量子密钥。
实验在 debian:forky-20261005-slim 中进行,使用 Debian 软件包 sq 1.4.1(sequoia-openpgp 2.4.1,Nettle 后端)和 gnupg 2.4.9;GnuPG 2.5.24 则在同一镜像中由发布源码包编译而成,编译前 gpg --verify 报告该源码包带有来自“Werner Koch (dist signing 2020)”的有效签名。所有密钥都是为本文专门生成的。
2023年以来的两个标准
OpenPGP 的上一版规范 RFC 4880 发布于2007年。对它的修订让社区产生了分裂。IETF 工作组的成果后来成为 RFC 9580;GnuPG 的开发者不认同其中的部分内容,于是把更早的草案延续为 LibrePGP(draft-koch-librepgp,由 Werner Koch 和 Ronald Henry Tse 个人提交的互联网草案,2026年9月发布的修订版 06),采用第 5 版密钥和一种不同的认证加密模式。对于新的密钥和消息格式,两者互不兼容;对于旧格式,两者依然兼容:所有实现都还能读写 v4 密钥和 v4 签名。
RFC 9580 对旧格式的表态很直接:“OpenPGP 实现应当(SHOULD)创建第 6 版格式的密钥。第 4 版密钥已被弃用;实现不应(SHOULD NOT)生成第 4 版密钥,但应当(SHOULD)接受它”(§5.5.2)。它定义了第 2、3、4 和 6 版密钥数据包;第 5 版只存在于 LibrePGP 中。它的其他变化包括:
- Ed25519(算法 27)和 X25519(25)是必须实现的算法;RSA“密钥已被弃用,不应(SHOULD NOT)生成,但可以解析”,DSA 和 ElGamal 则不得生成(§9.1)。
- v6 指纹是密钥的“256 位 SHA2-256 哈希”(§5.5.4.3);v4 指纹是 160 位的 SHA-1。
- v6 签名带有随机的盐值,因此被签名的哈希无法事先预测。
- 加密数据使用带 AEAD 的 SEIPD 第 2 版(OCB 为必须实现的模式),密码短语可以使用 Argon2。
Sequoia:按需生成 v6 密钥
sq key generate 默认创建 v4 密钥。它的帮助文本解释了原因:“目前默认值是 RFC4880。不过,等对 RFC9580 的支持进一步普及后,sq 的未来版本将更改默认值。”加上 --profile rfc9580 后,它会创建 v6 密钥:
sq key generate --own-key --without-password --name "Alice" --email alice@example.org --output alice-v4.pgp --rev-cert alice-v4.rev
sq key generate --own-key --without-password --profile rfc9580 --name "Alice" --email alice@example.org --output alice-v6.pgp --rev-cert alice-v6.rev
sq inspect alice-v4.pgp
sq inspect alice-v6.pgp
sq packet dump alice-v6.pgp
### default profile (RFC 4880)
Fingerprint: D3AE271931915949BEC2B3EBE329E5163B93B0F5
Public-key algo: EdDSA
Subkey: 0C7A47DD70202F80B0FA90B4E5C2206CA540055E
Public-key algo: EdDSA
Subkey: 8E35A51EC584304842AD4D13528B152570EC6FAC
Public-key algo: EdDSA
### --profile rfc9580
Fingerprint: 01117FE27C0ACB8EEBCE0D6FE03730724C57DA9E25D0963276EAB7A9F7EE2FB3
Public-key algo: Ed25519
Subkey: 23542B454F5CEDE06B81D42A874CFCF5CAB1E1D59E905CF0FC11AC21DE44A9F0
Public-key algo: X25519
Secret-Key Packet, new CTB, 75 bytes
Version: 6
Pk algo: Ed25519
从指纹就能看出区别:v4 是 40 个十六进制数字(SHA-1),v6 是 64 个(SHA-256)。v4 密钥使用较早的 EdDSA 算法标识符(22,RFC 9580 中称为“EdDSALegacy”),v6 密钥则使用新的专用算法 Ed25519(27)和 X25519(25)。用 v6 密钥生成的分离签名中可以看到盐值:
Signature Packet, new CTB, 152 bytes
Version: 6
Pk algo: Ed25519
Hash algo: SHA512
Issuer Fingerprint: A3B490FC8C54F12C1E4955E520071CDC4ECA7F76BC87729C2F7BA5305EAC6FC7
Salt: 62A29ACDACACD8ACF2D7ECDAAF3A10A6F577EDA3338E349D537190C437875B0F
Authenticated signature made by 01117FE27C0ACB8EEBCE0D6FE03730724C57DA9E25D0963276EAB7A9F7EE2FB3 (Alice)
1 authenticated signature.
库已经支持后量子密钥:sequoia-openpgp 2.4.0“增加了对 RFC 9980 所定义的后量子密码的支持”,sq 也列出了 mldsa65-ed25519 和 mldsa87-ed448 两种密码套件。但 PQC 代码只存在于 OpenSSL 和 RustCrypto 后端中,而 Debian 构建 Sequoia 时用的是 Nettle:
Error: Unsupported public key algorithm: ML-DSA-65+Ed25519
发行版选用了哪个密码学后端,决定了你究竟有没有后量子 OpenPGP 可用;sq version 会打印出这个后端。
GnuPG:LibrePGP、Kyber 以及从 2.4 到 2.5 的过渡
2025年12月30日,GnuPG 2.5 成为稳定系列,GnuPG 当时宣布“旧稳定版 2.4 系列将在短短 6 个月后结束生命周期”(gnupg.org);当前版本是 2.5.24(2026年9月23日)。发行版跟进得很慢:Debian 的 testing 分支仍然提供 2.4.9。该版本的默认密钥是带 Cv25519 子密钥的 v4 Ed25519 密钥:
pub ed25519 2026-10-22 [SC] [expires: 2027-10-22]
sub cv25519 2026-10-22 [E]
version 4, algo 22, created 1792651599, expires 0
version 4, algo 18, created 1792651599, expires 0
GnuPG 在 2.5 中加入了后量子加密:ML-KEM(Kyber)与一条经典曲线的组合,采用 LibrePGP 格式。到目前为止,它在后量子方面的工作只涉及加密;版本说明中没有列出任何后量子签名密钥。对于 2.5.23 中加入、需用 --allow-9980 启用的 RFC 9980 支持,它的文档有一段少见的直白描述:“由于规范臃肿,不建议使用此选项。GnuPG 的标准模式更倾向于经典 PGP,因而也就是 LibrePGP 规范;后者同样提供 PQC 支持,但方式更精简,更具 PGP 风格。”
互操作性实测
我们在三种实现之间交换了每一个密钥。首先是 GnuPG 2.4.9 读取 Sequoia 的密钥和签名:
gpg: key E329E5163B93B0F5: public key "Alice" imported
gpg: imported: 1
gpg: packet(6) with unknown version 6
gpg: read_block: read error: Invalid packet
--- gpg --verify of a v4 signature made by sq
gpg: using EDDSA key 0C7A47DD70202F80B0FA90B4E5C2206CA540055E
gpg: Good signature from "Alice" [unknown]
--- gpg --verify of the v6 signature
gpg: packet(2) with unknown version 6
gpg: no signature found
然后是 GnuPG 2.5.24 的后量子密钥,分别由 GnuPG 2.4.9 和 sq 1.4.1 读取:
### gpg --quick-gen-key ... pqc
pub brainpoolP384r1 2026-10-22 [SC] [expires: 2027-10-22]
sub ky768_bp256 2026-10-22 [E]
version 4, algo 19, created 1792651785, expires 0
version 5, algo 8, created 1792651785, expires 0, pkbytes 1265
gpg 2.4.9 --import, then --list-keys:
gpg: imported: 1
pub brainpoolP384r1 2026-10-22 [SC] [expires: 2027-10-22]
sub unknown_8 2026-10-22 [E]
sq 1.4.1 inspect:
Public-key algo: ECDSA
Unknown component: ... tag: PublicSubkey, error: Malformed packet: unknown version ...
### gpg --allow-9980 --quick-gen-key ... pqc9980
pub ietf27 2026-10-22 [SC] [expires: 2027-10-22]
sub mlk768_bp384 2026-10-22 [E]
version 6, algo 27, created 1792651785, expires 0, pkbytes 32
version 5, algo 39, created 1792651785, expires 0, pkbytes 1281
gpg 2.4.9 --import, then --list-keys:
gpg: packet(6) with unknown version 6
gpg: import from 'frank.pgp' failed: Invalid keyring
sq 1.4.1 inspect:
Public-key algo: Ed25519
Unknown component: ... tag: PublicSubkey, error: Malformed packet: unknown version ...
### gpg --allow-9980: v6 Ed25519 primary + mlk768 and mlk768_bp384 subkeys
version 6, algo 27, created 1792651848, expires 0, pkbytes 32
version 5, algo 35, created 1792651848, expires 0, pkbytes 1216
version 5, algo 39, created 1792651848, expires 0, pkbytes 1281
由此可见:
- v4 密钥和签名处处可用。sq 的默认密钥及其签名都在 GnuPG 2.4.9 中验证通过。
- v6 密钥止步于 GnuPG 2.4,报错
packet(6) with unknown version 6。把你的 v6 密钥导入 2.4 密钥环的人什么也得不到;v6 签名则只会得到“no signature found”。 - GnuPG 默认的 PQC 密钥仅适用于 LibrePGP。
pqc创建了一个 brainpoolP384r1 主密钥,外加一个放在 v5 数据包中的 Kyber-768 + brainpoolP256r1 子密钥(算法 8)。GnuPG 2.4.9 能导入它,但把子密钥列为unknown_8,因此无法用它加密;Sequoia 则拒绝这个 v5 数据包。 - 即使用“9980 模式”,也没能生成 Sequoia 能读取的密钥。使用
--allow-9980时,GnuPG 2.5.24 创建了 v6 主密钥,却把它的 ML-KEM 子密钥(包括mlk768,即算法 35,RFC 9980 中的 ML-KEM-768+X25519)写成了第 5 版数据包,而 RFC 9580 没有定义这种数据包,Sequoia 也会拒绝。pqc9980的默认设置还选用了算法 39,即 ML-KEM-768 搭配 brainpoolP384r1,它并不在 RFC 9980 自己定义的算法之列。截至 GnuPG 2.5.24,GnuPG 生成的 RFC 9980 密钥与 RFC 9980 实现仍然对接不上。
在 GnuPG 2.5 内部,所有这些密钥的加密和解密都能正常工作;问题只出在不同实现之间。
后量子 OpenPGP:RFC 9980 定义了什么
RFC 9980(拟议标准,2026年)新增了复合算法和独立算法:
| ID | 算法 | 要求 | 密钥 |
|---|---|---|---|
| 30 | ML-DSA-65+Ed25519 | 必须(MUST) | v6 |
| 31 | ML-DSA-87+Ed448 | 应当(SHOULD) | v6 |
| 32~34 | SLH-DSA-SHAKE-128s、128f、256s | 可以(MAY) | v6 |
| 35 | ML-KEM-768+X25519 | 必须(MUST) | v4 或 v6 |
| 36 | ML-KEM-1024+X448 | 应当(SHOULD) | v6 |
复合意味着两个部分都必须成功:攻击者必须同时攻破 ML-KEM 和 X25519,或者同时攻破 ML-DSA 和 Ed25519。加密是更紧迫的一半,因为加密消息可以现在存下来、将来再解密(“先收集后解密”)。签名可以等到验证方支持后再迁移,长期有效的签名以后也可以重新生成。由于 ID 35 也允许用于 v4 子密钥,现有的 v4 密钥可以添加一个后量子加密子密钥,而无需更换主密钥。
实用建议
- 用于发布版本、Git 提交和软件包的签名密钥:v4 Ed25519,用 GnuPG 2.4/2.5(
default)或 sq(默认配置)创建。我们测试过的每个验证工具都接受这类密钥。Debian 的 APT 现在默认用 Sequoia 的sqv验证归档签名(APT 3.0,Debian 13),并且自2026年2月1日起拒绝使用 SHA-1 绑定的签名和 v3 签名,因此所有旧内容都应重新签名(LWN 关于 APT 3.0 的文章)。 - 不要向你无法掌控的受众发布 v6 密钥,直到他们的工具换成 Sequoia、OpenPGP.js 6(它实现了 RFC 9580)或其他 RFC 9580 实现为止;GnuPG 2.4 用户无法导入这类密钥。
- 带后量子保护的加密目前只能在同一种方言内部使用:GnuPG 与 GnuPG 之间用 LibrePGP Kyber,或者用带 OpenSSL 或 RustCrypto 后端的 Sequoia 实现 RFC 9980。根据由谁解密来决定。
- 检查你的后端和版本(
gpg --version、sq version);发行版的软件包会落后上游一年甚至更久。 - 在不需要 OpenPGP 灵活性的场合,优先选择更简单的工具:Git 提交用 SSH 签名,发布版本的来源证明用 Sigstore,文件加密用 age。对比文章 SSH 与 GPG 提交签名对比、Sigstore 与 GPG 对比和 age 与 GPG 对比分析了其中的取舍;2026年的 ssh-keygen 介绍了 SSH 方面的做法。
- 公布完整的指纹,放在别人能核对的地方(你的网站、版本说明),并通过 WKD 或 keys.openpgp.org 分发密钥。密钥服务器只负责传递密钥,并不为密钥担保。
验证下载文件的正确做法
F-Droid 在 APK 旁边提供分离签名,并在网站上公布其签名密钥的指纹。验证只需三条命令:
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 37D2C98789D8311948394E3E41E7044E1DBA2E89
gpg --verify F-Droid.apk.asc F-Droid.apk
gpg --list-packets F-Droid.apk.asc
gpg: key 41E7044E1DBA2E89: public key "F-Droid <admin@f-droid.org>" imported
gpg: Signature made Mon Oct 12 12:58:48 2026 UTC
gpg: using RSA key 802A9799016112346E1FEFF47A029E54DD5DCE7A
gpg: Good signature from "F-Droid <admin@f-droid.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
Primary key fingerprint: 37D2 C987 89D8 3119 4839 4E3E 41E7 044E 1DBA 2E89
Subkey fingerprint: 802A 9799 0161 1234 6E1F EFF4 7A02 9E54 DD5D CE7A
:signature packet: algo 1, keyid 7A029E54DD5DCE7A
version 4, created 1791809928, md5len 0, sigclass 0x00
digest algo 10, begin of digest 4b be
“WARNING: This key is not certified”这一行是正常的:GnuPG 的信任网中没有通向这个密钥的路径。让这次检查真正有意义的,是把主密钥指纹与 F-Droid 验证页面上的指纹比对(两者一致),并在获取密钥时要求完整指纹,因为密钥服务器会交出任何与之匹配的密钥。签名本身是基于 SHA-512(摘要算法 10)的 v4 RSA 签名(算法 1):格式旧,哈希新,所有实现都能读取。如果缺少密钥,你会看到 Can't check signature: No public key;如果文件被改动过,则会看到 BAD signature。
来源
- RFC 9580:OpenPGP(2024年7月):§5.5.2(密钥版本)、§5.5.4(指纹)、§9.1(算法)、表 27
- RFC 9980:OpenPGP 中的后量子密码(2026年)及其 IETF Datatracker 条目
- GnuPG:新闻、NEWS 文件(2.5.0 的 Kyber、2.5.23 的
--allow-9980)、2.5.24 发布包中的doc/gpg.texi - Sequoia:sequoia-openpgp NEWS(2.0.0 的 RFC 9580、2.4.0 的 RFC 9980)、
sq key generate --help(1.4.1) - LWN:APT 3.0 有哪些新变化;F-Droid:验证下载的 APK