GPG 与 YubiKey 的配置与使用
之前买了两个 YubiKey,一直只使用 OTP 和 FIDO 功能,今天把 GPG 也配置上。
本文基于 macOS 进行配置。

配置
首先安装:brew install gnupg。
YubiKey 的配置
你可以使用 ykman openpgp reset --force 来直接重置 OpenPGP 应用,但这会清除卡上已有的 OpenPGP 密钥、证书和相关配置。执行前请确认已经做好离线备份。
修改默认 PIN
如果是第一次使用或者刚重置,需要先修改默认 PIN。
1 | # 插入 YubiKey |
修改密钥算法
这一步需要在写入密钥前完成。YubiKey 5.2.3 及以上固件支持 Curve25519;签名和认证槽实际使用 Ed25519,加密槽实际使用 X25519。
1 | gpg --card-edit |
GPG 的配置
创建主密钥
首先使用 gpg --full-generate-key --expert 生成主密钥,选择 (11) ECC (set your own capabilities) 和 (1) Curve 25519,用途仅保留 Certify。主密钥只用于管理身份和子密钥,日常签名、加密和 SSH 认证都交给子密钥。
生成完成后记录主密钥指纹:
1 | gpg --list-secret-keys --with-subkey-fingerprint --with-keygrip |
本文后面出现的 <FINGERPRINT> 均替换为主密钥指纹;Keygrip 只在 SSH 配置的 sshcontrol 中使用。
生成子密钥
子密钥这里设置为 1 年有效期。写入 YubiKey 后,私钥材料无法再从 YubiKey 导出;如果没有提前备份,后续就不能再复制到另一把 YubiKey。过期前可以用离线保存的主密钥延长子密钥有效期。
1 | # 进入密钥编辑模式(替换为实际主密钥指纹) |
写入 YubiKey
在这里,我会写入多个 YubiKey。正常情况下,keytocard 成功并 save 后,本地的子密钥私钥会被替换为指向该卡的 stub,所以如果想要将同一份子密钥写入多个 YubiKey,需要先备份子密钥,并且每写一把新卡都从备份恢复一次。
备份密钥
1 | gpg --armor --export-secret-keys <FINGERPRINT> > master-secret.asc |
写入 YubiKey
恢复密钥
如果是第一次写入 YubiKey,可以直接使用当前密钥环;如果要写入第二把或更多 YubiKey,建议使用临时 GNUPGHOME 从备份恢复密钥后再写入。
1 | mkdir ./tmp-gpghome |
插入 YubiKey
1 | gpg --edit-key --expert <FINGERPRINT> |
清理并备份
先导出信任数据库和吊销证书:
1 | gpg --export-ownertrust > ownertrust.txt |
然后删除本地的主密钥私钥,只保留 YubiKey 子密钥 stub:
1 | gpg --delete-secret-keys '<FINGERPRINT>!' |
这里的 ! 表示只删除主密钥的私钥部分,不删除子密钥 stub。最后将 master-secret.asc、subkeys-secret.asc、public.asc、ownertrust.txt 和 revoke-cert.asc 离线保存。其中 public.asc 可以公开。
使用
SSH
首先检查是否开启 SSH 支持:
1 | grep -qxF 'enable-ssh-support' ~/.gnupg/gpg-agent.conf || echo 'enable-ssh-support' >> ~/.gnupg/gpg-agent.conf |
然后重启 agent:
1 | gpgconf --kill gpg-agent |
添加环境变量:
可以添加到 Shell 启动脚本
1 | export GPG_TTY="$(tty)" |
如果 ssh-add -L 没有输出认证子密钥,需要把认证子密钥的 Keygrip 写入 sshcontrol:
1 | gpg --list-secret-keys --with-keygrip <FINGERPRINT> |
最后通过 ssh-add -L 导出公钥,并放入到服务器的 ~/.ssh/authorized_keys 中即可。