7.0 KiB
虽说更多时候还是防自己, 但是整一套 GPG 密钥体系真的很酷, 多点安全感也绝不是坏事.
Warning
仅记录我的折腾过程, 并非指南, 并非推荐, 并非技术文档.
What?
PGP (Pretty Good Privacy) 是一种数据加密和解密的程序, GnuPG (GNU Privacy Guard) 是 PGP 的一个开源实现. GPG, PGP, 真是好名字.
How?
-
生成密钥对:
gpg --full-generate-key按照提示选择密钥类型、大小和有效期, 并输入用户信息 (如姓名和电子邮件地址) 和密码.
-
列出密钥:
gpg --list-secret-keys --keyid-format=long从中找到刚刚生成的密钥, 例如:
sec ed25519/ABCDEF1234567890 2026-01-01 [SC] 1234567890ABCDEF1234567890ABCDEF12345678 uid [ultimate] Uyanide <email@domain.tld> ssb cv25519/1234567890ABCDEF 2026-01-01 [E]其中
ABCDEF1234567890是主密钥 ID, 记下来. -
生成撤销证书:
gpg --output revoke.asc --gen-revoke ABCDEF1234567890将
ABCDEF1234567890替换为主密钥 ID. 撤销证书用于在密钥泄露或不再使用时撤销该密钥, 请离线妥善保管revoke.asc文件.
Important
离线 指的是不连接互联网的环境. 最好将撤销证书存储在物理介质上, 如 USB 驱动器或打印出来, 并放在安全的地方.
-
生成子密钥
GPG 密钥有四种主要功能标志:
C(Certify): 用于签署其他密钥.S(Sign): 用于签署数据 (如电子邮件或 git 提交).E(Encrypt): 用于加密数据.A(Authenticate): 用于身份验证 (如 SSH).
主密钥通常只用于
C功能, 默认也会有S功能. 但是在最佳实践中, 主密钥应只用于C功能, 其他三种功能由至少三个不同的子密钥承担, 日常使用也多使用子密钥而非主密钥.-
对于
S和E功能, 可以通过以下命令添加子密钥:gpg --edit-key ABCDEF1234567890进入交互式界面后, 使用以下命令:
addkey: 添加子密钥, 按照提示选择密钥类型和大小.save: 保存并退出.
-
对于
A功能, 可能需要启用 expert 模式:什么, 专家? 我?
gpg --expert --edit-key ABCDEF1234567890进入交互式界面后, 使用以下命令:
addkey: 添加子密钥- 选择
(set your own capabilities)后缀的选项作为密钥类型. - 通过交互式操作仅保留
A功能. Q完成密钥功能的设置, 并按照提示选择密钥类型和大小.save: 保存并退出.
Note
和更换麻烦的主密钥相比, 子密钥建议设置为较短的有效期.
Tip
即使日常使用不同的子密钥做不同的事, 但实际分享公钥或配置软件时使用的公钥以及密钥 ID 通常仍然是主密钥的公钥和密钥 ID, 而非具体所使用的子密钥的公钥和密钥 ID.
-
添加用户 ID
有些时候需要添加额外的用户 ID (如其他电子邮件地址).
gpg --edit-key ABCDEF1234567890进入交互式界面后, 使用以下命令:
adduid: 添加新的用户 ID, 按照提示输入姓名和电子邮件地址.save: 保存并退出.
Note
很多平台要求密钥包含在平台经过验证的电子邮件地址, 否则无法使用该密钥进行加密通信.
-
导出公钥
gpg --armor --export ABCDEF1234567890 > publickey.asc将
ABCDEF1234567890替换为主密钥 ID. 这会将公钥导出到publickey.asc文件中, 可以将其大大方方地分享给他人.
Important
每次完成对已有 GPG 密钥的修改(如添加用户 ID, 添加子密钥等)后, 都需要重新导出和更新公钥.
-
导出主密钥的私钥
如果遵循最佳实践, 主密钥的私钥不应该长期保存在本地, 而只在需要时导入使用.
导出所有私钥到文件:
gpg --export-secret-keys --armor ABCDEF1234567890 > masterkey.asc gpg --export-secret-subkeys --armor ABCDEF1234567890 > subkeys.asc随后移除本地所有私钥:
gpg --delete-secret-keys ABCDEF1234567890再导入先前导出的子私钥:
gpg --import subkeys.asc验证:
gpg --list-secret-keys --keyid-format=long如果输出的第一行变为
sec#开头, 则表示主密钥的私钥已从 keyring 中移除, 只剩下其 Stub.请妥善离线保管
masterkey.asc, 它是恢复主密钥的唯一途径.
Important
与 SSH 密钥不同, GPG 密钥应在多设备间同步, 以便在任何设备上都能向别人验证自己的身份以及进行加密通信.
-
设置信任等级
为了让 GPG 确认密钥是可信的, 有些情况下需要手动为其设置信任等级.
gpg --edit-key ABCDEF1234567890进入交互式界面后, 使用以下命令:
trust: 选择5 = I trust ultimately作为信任等级.save: 保存并退出.
Why?
举个例子, 使用 GPG 密钥对 git 提交进行签名, 参见 Github 文档: Adding a GPG key to your GitHub account 和 Telling Git about your signing key
One More Thing ...
通过 gpg-agent, GPG 密钥可以作为 SSH 密钥使用, 这真的很酷统一了密钥管理的同时也增加了一些安全性. 论使用体验其实目前的 ssh-init 方案已经足够满足我的要求了, 但它真的很酷.
总之, 记录一下折腾过程吧.
-
添加认证子密钥
参考上文, 添加一个仅带有
A(Authenticate) 功能的子密钥. -
告诉 GPG 启用 SSH 支持
编辑
~/.gnupg/gpg-agent.conf, 添加或修改以下行:enable-ssh-support可选地, 设置缓存有效期 (这对于拥有密码管理系统的桌面来说用处不大):
default-cache-ttl 600 max-cache-ttl 7200 -
绑定密钥
首先, 获取认证子密钥的 Keygrip:
gpg --list-secret-keys --with-keygrip ABCDEF1234567890输出类似:
ssb ed25519 2026-01-16 [A] Keygrip = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX然后将其写入
~/.gnupg/sshcontrol文件中:echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" >> ~/.gnupg/sshcontrol -
启动!
参见 gpg-init 脚本.
eval $(gpg-init)此时环境变量
SSH_AUTH_SOCK已指向 gpg-agent 提供的 SSH 代理套接字, 可以像使用普通的 ssh-agent 一样使用 GPG 代理进行 SSH 认证. -
获取公钥
获取 SSH 公钥以添加到远程服务器或服务:
ssh-add -L