.webp)
GPG 使用教程(2026):命令行、Git 提交签名、YubiKey 配置、大型文件加密
GnuPG (GPG) 完整使用指南
适用读者:开发者、系统运维、安全工程师,以及需要加密文件、签名 Git 提交或保护敏感数据的任何人。
前置知识:基本的命令行操作(会打开终端、执行命令即可),无需 GPG 基础。
版本说明:本文基于 GnuPG 2.2+,YubiKey 相关操作需要固件 5.x 以上。
本文特色:
- 📦 覆盖日常所有场景:密钥管理、加密解密、签名验证
- 🔗 深度集成 Git(提交签名、多密钥管理、条件包含)
- 🔐 高级专题:硬件密钥(YubiKey)迁移、大文件分卷加密、隐私隐藏(
--throw-keyids) - 🧰 故障排查表、安全最佳实践、撤销证书完整流程
篇幅较长(约 2 万字),建议按需跳读:
- 新手请从「一、基础概念」开始顺序阅读
- 开发者重点关注「五、与 Git 集成」和「六、同时管理多个私钥」
- 追求极致安全直接跳到「十五、配置硬件密钥」
- 处理大文件或备份请查看「十六、大型文件加密与签名」
本文是你的一站式 GPG 参考手册,建议收藏。
一、基础概念
- 密钥对:一个公钥 + 一个私钥。公钥公开,私钥保密。
- 公钥:用于加密和验证签名。
- 私钥:用于解密和签署文件/提交。
- Key ID:密钥的唯一标识符(通常是最后8位或16位十六进制)。
- 密钥环:存放密钥的数据库(
pubring.kbx/secring.gpg)。 - 信任网络:通过互相签名建立的信任体系(Web of Trust)。
二、密钥管理
2.1 生成密钥对
1 | gpg --full-generate-key |
根据提示:
- 密钥类型:默认
RSA and RSA - 密钥长度:
4096(推荐) - 有效期:
1y(一年)或0(永不过期) - 用户ID:真实姓名和邮箱(必须与你 Git / GitHub 邮箱一致)
- 密码:保护私钥的密码(一定要记住)
2.2 列出所有密钥
1 | # 列出公钥(显示 Key ID) |
2.3 删除密钥
1 | # 删除公钥(需要先删除私钥) |
2.4 导出密钥
1 | # 导出公钥(ASCII 格式,适合粘贴) |
2.5 导入密钥
1 | gpg --import public-key.asc |
2.6 编辑密钥(例如设置信任等级)
1 | gpg --edit-key <Key ID> |
常用子命令:trust (设置信任),sign (签名对方公钥),adduid (添加用户ID),expire (修改有效期)。
三、加密与解密
场景1:用对方公钥加密文件(只有对方能解密)
1 | gpg --encrypt --armor --recipient <对方邮箱> 文件.txt |
--encrypt:加密模式--armor:输出 ASCII 文本(否则是二进制)--recipient:指定接收者的公钥(使用其邮箱)- 输出:
文件.txt.asc
场景2:解密收到的加密文件
1 | gpg --decrypt 文件.txt.asc > 文件.txt |
系统会提示输入你的私钥密码。
场景3:给自己加密(用自己的公钥加密)
1 | gpg --encrypt --armor --recipient <你的邮箱> 敏感数据.txt |
只有你自己(持有对应私钥)能解密。
场景4:对称加密(使用同一密码加密/解密)
1 | # 加密 |
适合快速保护文件,不需要管理密钥对。
四、签名与验证
场景5:签署文件(生成包含原文+签名的文件)
1 | gpg --sign --armor 文档.pdf |
输出 文档.pdf.asc,接收方可以用 gpg --verify 验证。
场景6:分离签名(文件与签名分开)
1 | gpg --detach-sign --armor 软件包.zip |
生成 软件包.zip.asc 独立签名文件。
验证时需同时持有原文件和签名:
1 | gpg --verify 软件包.zip.asc 软件包.zip |
场景7:清除签名(只输出原文)
1 | gpg --clear-sign 消息.txt |
生成 消息.txt.asc,内容是 ASCII 格式的原文+签名。
场景8:验证下载的软件签名(常见于开源项目)
1 | gpg --verify 软件.tar.gz.asc 软件.tar.gz |
显示 Good signature 表示文件未被篡改且来源可信。
五、与 Git 集成(提交签名)
9. 配置 Git 使用 GPG 签名
1 | # 设置签名所用的 Key ID |
10. 手动签名某次提交
1 | git commit -S -m "提交信息" |
11. 查看提交的签名状态
1 | git log --show-signature -1 |
12. 将公钥添加到 GitHub / GitLab
1 | gpg --export --armor <你的Key ID> |
复制输出的公钥,粘贴到 GitHub → Settings → SSH and GPG keys → New GPG key。
六、同时管理多个私钥
13. 列出所有私钥并区分用途
1 | gpg --list-secret-keys --keyid-format=long |
输出示例:
1 | sec rsa4096/AAAAAAAAAAAA 2025-01-01 [SC] [expires: 2026-01-01] |
14. 为不同 Git 仓库选择不同的签名密钥
方法一:在仓库内单独设置
1 | cd 项目A |
方法二:使用 Git 条件包含(推荐)
在 ~/.gitconfig 中:
1 | [includeIf "gitdir:~/work/"] |
然后分别创建 .gitconfig-work 和 .gitconfig-personal,各自设置 user.signingkey。
15. 加密时指定特定的接收者
1 | gpg --encrypt --recipient work@company.com --recipient personal@gmail.com 文件.txt |
这样两个接收者都能用自己的私钥解密。
16. 导出/导入特定密钥(避免混淆)
1 | # 导出指定密钥 |
17. 设置默认密钥(用于加密/签名)
1 | # 设置默认签名密钥 |
七、密钥服务器操作
18. 将公钥上传到公共服务器
1 | gpg --keyserver keyserver.ubuntu.com --send-keys <你的Key ID> |
19. 从服务器下载他人公钥
1 | gpg --keyserver keyserver.ubuntu.com --recv-keys <对方Key ID> |
20. 刷新所有已导入的公钥(获取最新有效期)
1 | gpg --refresh-keys |
八、维护与故障排查
21. 检查密钥有效期
1 | gpg --list-keys --keyid-format=long |
注意 [expires: YYYY-MM-DD] 标记。
22. 延长密钥有效期
1 | gpg --edit-key <你的Key ID> |
在交互环境中输入 expire,按提示修改,最后 save。
23. 签名他人的公钥(建立信任)
1 | gpg --sign-key <对方Key ID> |
24. 导出带有你自己签名的公钥(给别人)
1 | gpg --export --armor <你的Key ID> > my-signed-pub.asc |
25. 重启 GPG 代理(解决锁文件问题)
1 | gpgconf --kill all |
26. 查看 GPG 配置和路径
1 | gpg --version |
九、安全最佳实践
- 私钥绝不上传网络,备份到加密 U 盘或硬件安全密钥(如 YubiKey)。
- 定期延长有效期(例如每年一次)。
- 使用强密码保护私钥(至少 12 位,含大小写+数字+符号)。
- 撤销证书:生成密钥时同时生成撤销证书
gpg --gen-revoke <Key ID>,并存放在安全地方(万一私钥泄露可用它宣告该密钥作废)。 - 在公共电脑上避免使用
--import私钥,改用--encrypt和--decrypt时要确保环境可信。
十、常见错误信息及解决
| 错误信息 | 含义 | 解决方法 |
|---|---|---|
No secret key |
找不到私钥 | 检查user.signingkey 或 --recipient 是否正确,确认密钥已导入且未被删除。 |
gpg: signing failed: Inappropriate ioctl for device |
无法弹出密码输入窗口 | 设置环境变量export GPG_TTY=$(tty)(Linux/macOS)或安装 pinentry。 |
gpg: keyblock resource ...: No such file or directory |
路径转换错误(Windows 常见) | 设置set MSYS_NO_PATHCONV=1 或清除 GNUPGHOME 环境变量。 |
gpg: Can't check signature: No public key |
缺少对方的公钥 | 用gpg --recv-keys 下载对方公钥。 |
gpg: Invalid passphrase |
密码错误 | 确认密码大小写,或重新设置私钥密码(gpg --edit-key <Key ID> → passwd)。 |
十一 密钥撤销证书
撤销证书是你在私钥丢失、泄露或更换邮箱时,用来通知外界你的公钥作废的“紧急销毁开关”。 必须提前生成并妥善保管。
整个流程分为生成、保存和发布三步:
1. 提前生成撤销证书(✅ 推荐)
生成密钥对后,应立即生成撤销证书。这让你在忘记密码或私钥泄露时,仍有办法控制公钥的“生死”。
标准命令:
1 | # 推荐使用输出重定向,直接将证书写入文件 |
选项说明:
--output指定文件,省略会直接打印到屏幕。- 交互式确认:命令执行后,会询问撤销原因,通常是
1(Key has been compromised,密钥泄露) 或2(Key is superseded,密钥已被替换)。
2. 严格保存
把生成的 mykey_revoke.asc 文件离线存放在安全的地方,例如加密U盘。绝对不要放在日常使用的 .gnupg 目录下,以免被误用或连同私钥一起丢失。
3. 必要时发布撤销信息
当需要正式停用该密钥时,执行导入操作:
1 | gpg --import mykey_revoke.asc |
导入后,你本地的公钥环会将该密钥标记为“已撤销”。同时,你应该将撤销后的公钥发布到密钥服务器,通知其他用户。
1 | # 将撤销后的公钥发送到公钥服务器 |
例如,使用 keys.openpgp.org 服务器。
⚠️ 重要警告
如果私钥丢失且没有提前生成撤销证书,则无法撤销该公钥。因此,这是密钥管理中不可跳过的安全步骤。
撤销证书的使用分为两步:先在本地导入使密钥失效,再同步到公钥服务器通知他人。
一、何时需要使用撤销证书?
- 私钥丢失或忘记密码
- 私钥被泄露(被盗、病毒等)
- 更换新密钥(旧密钥不再使用)
- 邮箱地址变更,不再使用旧密钥
一旦导入撤销证书,该密钥在你本地就会标记为“已撤销”,之后不能再用于签名或解密(但之前已签名的数据仍可验证)。
二、使用步骤
1. 导入撤销证书到你的 GPG 密钥环
1 | gpg --import mykey_revoke.asc |
执行后会看到类似输出:
1 | gpg: key 3DA13E2330595E7C: "DeLiSha (main) <L750243132@outlook.com>" revocation certificate imported |
此时再查看你的公钥:
1 | gpg --list-keys --keyid-format=long |
你会看到该密钥后面多了 revoked 字样,例如:
1 | pub rsa4096/3DA13E2330595E7C 2026-05-18 [SC] [revoked: 2026-05-18] |
注意:导入撤销证书后,这个操作不可逆。即使你后来找回私钥,也无法撤销这个撤销操作。所以在真正决定停用该密钥之前不要执行。
2. 将已撤销的公钥发布到公钥服务器(通知全世界)
为了让其他用户不再信任这个已撤销的密钥,需要将带有撤销状态的公钥上传到公共密钥服务器。
1 | gpg --keyserver keyserver.ubuntu.com --send-keys 3DA13E2330595E7C |
也可以使用其他服务器,如 keys.openpgp.org。
上传后,任何人从服务器下载你的公钥时,都会看到它已被撤销。他们使用你的旧公钥验证签名时,GPG 会提示 WARNING: This key has been revoked by its owner!。
3. 通知与你通信的人(可选但推荐)
对于常用的协作对象(同事、开源项目维护者),你可以单独告知:“我的旧 GPG 密钥已撤销,新密钥是 XXXXXXXX”。这比依赖公钥服务器更直接。
三、验证撤销是否生效
本地测试
1 | gpg --list-keys --with-colons | grep -A1 "3DA13E2330595E7C" |
如果出现 rev 标识,表示已撤销。
从服务器重新下载测试
1 | gpg --keyserver keyserver.ubuntu.com --recv-keys 3DA13E2330595E7C |
你会看到 revoked 标记。
四、重要安全提示
- 撤销证书不要随意导入,一旦导入就不可逆。仅在你确实要废弃该密钥时使用。
- 导入撤销证书不需要私钥(即使私钥已丢失也可操作)。所以保管好撤销证书本身很重要,防止他人恶意撤销你的密钥。
- 撤销后的密钥无法恢复。如果只是暂时不用,可以延长有效期或降低信任,而不是直接撤销。
- 最好先备份当前密钥环,再执行导入撤销证书:
1
cp -r ~/.gnupg ~/.gnupg-backup
五、完整示例(模拟场景)
假设你旧密钥 ID AAAAAAAAAAAAAAAA 泄露了,你提前生成过撤销证书 revoke.asc。
1 | # 1. 导入撤销证书 |
常用密钥服务器对比与使用指南
常用的几大服务器各有侧重,我为你整理了对比表格:
| 推荐指数 | 服务器地址 | 特点 | 适用场景 |
|---|---|---|---|
| ⭐⭐⭐⭐⭐ | keys.openpgp.org |
默认推荐。隐私性好,强制邮箱验证,能有效避免垃圾签名,但会移除第三方签名。 | 日常代码提交签名及日常通信。 |
| ⭐⭐⭐⭐ | keyserver.ubuntu.com |
社区主流。保留了完整的签名信息,可交叉验证信任链,不会移除此类信息,尽管它可能会移除第三方签名。 | 需要展示完整信任链的开发者或参与社区签名活动。 |
| ⭐⭐ | pgp.mit.edu (MIT) |
历史悠久,但速度慢,稳定性不佳。 | 兼容旧系统或文档指定使用。 |
| ⭐⭐ | keys.gnupg.net |
曾是官方推荐,现已弃用,维护状态不明。 | 不推荐使用,尽量避开。 |
十二 使用密钥服务器的实战指南
1. 设置默认服务器(推荐)
为了避免每次输入 --keyserver,可以将其设为默认:
1 | gpg --keyserver hkps://keys.openpgp.org --send-keys 你的KeyID |
hkps://表示使用更安全的加密连接。
2. 发布你的公钥
1 | gpg --send-keys 你的KeyID |
这是最直接的方式,但需注意,通过此方式发布到 keys.openpgp.org 的密钥默认不支持用邮箱搜索。
3. 接收他人的公钥
如果你知道对方的 KeyID(如 A0B1C2D3):
1 | gpg --recv-keys A0B1C2D3 |
4. 搜索他人的公钥
如果你知道对方的邮箱或名字,可以模糊搜索:
1 | gpg --search-keys l750243132@outlook.com |
💡 进阶技巧:确保你的密钥能用邮箱找到
如果你希望别人能通过你的邮箱直接搜到密钥(对 keys.openpgp.org 尤其重要),可以先导出一个临时文件:
1 | gpg --export 你的邮箱 > my_public_key.asc |
然后在 keys.openpgp.org 官网上传,系统会自动发送验证邮件到你的邮箱,点击链接即可完成邮箱绑定。
🌟 新趋势:无需服务器的 Web Key Directory (WKD)
WKD 是一种新技术,它能让邮件客户端直接从你的网站自动获取公钥,完全不需要依赖公共密钥服务器。
- 优势:你的公钥和你权威的个人网站直接关联,这是最安全、最可信的方式。
- 门槛:你需要拥有自己的个人域名和网站服务器,并且需要配置HTTPS。
结论
- 普通用户/开发者:选
keys.openpgp.org就足够了。 - 注重信任链的开发者:可以考虑
keyserver.ubuntu.com或自建 WKD。
十三 指定使用的密钥
在 GPG 签名(无论是文件签名还是 Git 提交签名)时,如果你有多个私钥,可以明确指定使用哪一个。以下是两种最常见场景的具体方法。
一、使用 gpg 命令行签名时指定密钥
通过 --local-user 或 -u 参数指定要使用的私钥(可以用 Key ID、邮箱或用户ID)。
1 | # 用 Key ID 指定 |
生成签名文件后,验证时需要用对应的公钥(GPG 会自动从密钥环中匹配)。
二、使用 git 提交时指定签名密钥
方法 1:临时指定(单次提交)
1 | git commit -S --gpg-sign=<你的Key ID> -m "提交信息" |
或者简写(如果已配置过 user.signingkey 但想临时覆盖):
1 | git commit -S<你的Key ID> -m "提交信息" |
方法 2:为当前仓库设置默认密钥
1 | cd 项目仓库 |
之后在该仓库中的所有提交(若开启了 commit.gpgsign true)都会使用这个密钥。
方法 3:全局默认密钥(影响所有仓库)
1 | git config --global user.signingkey <你的Key ID> |
注意:如果同时存在仓库级和全局级配置,仓库级优先。
三、验证当前使用的是哪个密钥
查看 Git 当前签名密钥配置
1 | git config user.signingkey |
查看某次提交实际使用的签名密钥
1 | git log --show-signature -1 |
输出中会显示 using RSA key <Key ID>。
查看 GPG 默认签名密钥(用于命令行)
1 | gpg --list-secret-keys --keyid-format=long |
若想设置全局 GPG 默认密钥(非 Git),可编辑 ~/.gnupg/gpg.conf 添加:
1 | default-key <你的Key ID> |
四、常见问题
Q:我指定了 Key ID,但报错 No secret key?
A:检查 Key ID 是否正确(gpg --list-secret-keys 查看),注意大小写,通常用完整长 ID(如 3DA13E2330595E7C)更准确。
Q:能不能用邮箱代替 Key ID?
A:可以,但前提是邮箱只有一个对应的私钥。若多个私钥绑定了同一邮箱,需要用 Key ID 区分。
Q:如何临时忽略默认配置,强制使用另一个密钥?
A:在 git commit 时加上 --gpg-sign=<其他Key ID> 即可覆盖 user.signingkey。
五、一句话总结
- GPG 命令:用
-u <Key ID>或--local-user - Git 提交:用
git commit -S<Key ID>或设置user.signingkey
十四 最大化隐私(隐藏私钥信息)
--throw-keyids 是 GPG 加密时的一个隐私增强选项。它的作用是:在加密数据的元数据中,不显式记录接收者的密钥 ID。
一、默认行为 vs --throw-keyids
默认加密(不加此选项)
1 | gpg --encrypt --recipient alice@example.com 文档.txt |
加密后的数据包中会包含一个“密钥 ID 列表”,明确写着“这个加密包是发给 alice@example.com 的公钥(Key ID xxxx)的”。任何拥有该公钥的人都能从密文元数据中直接看到接收者是谁(虽然无法解密)。
使用 --throw-keyids
1 | gpg --throw-keyids --encrypt --recipient alice@example.com 文档.txt |
加密后的数据包中,接收者密钥 ID 字段被填充为全零(或随机垃圾值),不泄露任何关于接收者身份的信息。攻击者拿到密文后,无法判断这是发给 Alice、Bob 还是 Charlie 的。
二、工作原理
- 正常情况下,GPG 将接收者的 Key ID 明文明文写在加密包的
Pubkey-Encrypted Session Key包中。 - 使用
--throw-keyids后,GPG 将这个 Key ID 字段设为 0x0000000000000000(8 字节零)。 - 解密时,接收方必须用自己所有的私钥依次尝试解密会话密钥,直到某个私钥成功解开。
- 如果你只有 1~2 个私钥,这个尝试过程很快(微秒级)。
- 如果你有几十个私钥,也基本无感知。
三、适用场景
| 场景 | 是否推荐--throw-keyids |
|---|---|
| 匿名举报、泄露敏感信息(不希望暴露接收者身份) | ✅ 强烈推荐 |
| 发送加密文件给特定同事(对方是你唯一接收人) | ⚠️ 可选,但通常没必要 |
多人加密(--recipient 列出多个接收者) |
⚠️ 需注意:所有接收者都会尝试各自的私钥,但密文体积会增大 |
| 自动化脚本、批量处理 | ❌ 不推荐(增加解密端处理时间) |
| 接收方使用硬件密钥(如 YubiKey)且私钥较多 | ⚠️ 可能触发多次 PIN 输入,体验差 |
四、使用示例
加密
1 | gpg --throw-keyids --armor --recipient alice@example.com --encrypt secret.txt |
解密(接收方无需特殊参数,正常执行即可)
1 | gpg --decrypt secret.txt.asc |
如果 Alice 有多个私钥,GPG 会依次尝试,直到成功。
五、与 --hidden-recipient 的关系
--hidden-recipient(-R)是--throw-keyids的同义词(同一功能的不同名称)。--recipient(-r)是显式指定接收者(默认不隐藏 Key ID)。
所以:
1 | gpg -R alice@example.com -e secret.txt # 等价于 --throw-keyids |
六、注意事项
- 兼容性:所有现代 GPG 版本都支持
--throw-keyids,解密时会自动尝试所有私钥。 - 性能影响:解密端需要遍历所有私钥,通常可以忽略(现代 CPU 毫秒级)。如果私钥数量 > 100 或使用智能卡(每次尝试需按确认),会明显变慢。
- 匿名性增强:即使加密数据被截获,攻击者不知道你发给谁。但仍需注意其他元数据(如文件名、时间戳、通信模式分析等)。
- 与密钥服务器的矛盾:如果使用
--throw-keyids加密,但接收者的公钥仍公开在密钥服务器上,攻击者仍可推测可能发给该用户。真正的强匿名需要配合 Tor 等使用。
七、总结
--throw-keyids让你的加密输出“对暗号”:只给出一串密文,不告诉这是给谁的。只有拿着正确私钥的人才能试出来。
适用:匿名通信、高度敏感的隐私保护场景。
不适用:日常办公、团队协作(增加复杂度,收益极低)。
十五 配置硬件密钥
是的,这正是现代加密实践中,用来保护私钥的最高安全方案。它的核心思想是把你的私钥,从随时可能被黑的电脑里,移到一个独立的、专为安全设计的硬件设备中。
下面从原理、优势到实战操作,一步步为你讲解。
什么是硬件密钥?
硬件密钥(如 YubiKey、Nitrokey 或智能卡),本质上是一个专门设计的、能独立执行密码运算的微型计算机。
- 不可提取性:私钥一旦写入设备,就会立刻锁定,永远无法以任何形式被读取或导出。攻击者即使完全控制了你的电脑,也无法通过网络偷走你的私钥。
- 运算隔离:加密/解密、签名/验证等密码操作,都在硬件内部完成。系统只将待处理数据和指令发送给设备,设备处理后再将结果返回,私钥全程不进入计算机内存。
- 防篡改设计:设备芯片本身设计为防篡改的,任何物理拆解都会导致内部电路自毁,保护数据安全。
为什么需要硬件密钥?核心优势
使用硬件密钥,相当于把你的身份凭证(私钥)从“软件”升级到了“硬件”级别,提供了多重保障。
- 🔒 防软件层面的黑客攻击:恶意软件无法扫描磁盘找到私钥文件,也不能从内存中提取私钥,因为它根本就不在电脑里。
- 🙌 物理接触授权:为所有敏感操作增加一个物理确认的动作,必须在设备上按下按钮才能完成,防止远程操控。
- 🤸 便携与跨平台:把密钥插在任何一台电脑上就能工作,无需手动分发和配置私钥文件,而且PIN码可以独立于电脑设置。
- 🛡️ 防止“加密勒索”:即使忘记拔下YubiKey,攻击者也只能在你连接时临时借用,而无法将你的私钥从设备中复制走。
哪些硬件密钥可以选?
只要支持 OpenPGP 智能卡规范的设备都可以使用。
- YubiKey 5 系列:是市面上最流行、兼容性最好的选择之一。选购时请务必选择 YubiKey 5 系列,并确认其支持 OpenPGP 功能,以确保可以进行签名和认证。
- Nitrokey / GNUK:完全开源的硬件方案,适合追求极致透明度的用户。
- TKey / LibreKey:其他兼容 OpenPGP 规范的 USB 设备,同样可以作为备选。
- PC/SC 智能卡:需要单独的读卡器,在企业环境中也有应用。
🔧 实战教程:如何用 YubiKey 为 Git Commit 签名
这部分我们来实际操作,将现有的 GPG 子密钥迁移到 YubiKey 上。
- 准备工作:
- 需要一个已准备好并备份的 GPG 主密钥(包含三个子密钥:
[S]签名、[E]加密、[A]认证)。 - YubiKey 插入电脑后,运行
gpg --card-status命令,若看到“Application ID … D27600012401…”等信息,则表示连接成功。
- 需要一个已准备好并备份的 GPG 主密钥(包含三个子密钥:
接下来,我们分为三步走:
第一步:配置你的 YubiKey
开启 admin 模式,强烈建议先启用 KDF(密钥派生函数),它能存储 PIN 的哈希值,提高安全性。同时,务必修改默认的 PIN 和 Admin PIN。
- 进入编辑模式并开启管理:
1
2
3gpg --card-edit
gpg/card> admin
gpg/card> kdf-setup # 启用KDF,这一步建议先做! - 修改你的PIN码(根据提示输入4-8位新密码):
1
gpg/card> passwd
- 配置触摸策略(可选,建议):设置后,每次使用都需要物理触摸一下YubiKey的感应区。
1
gpg/card> forcesig # 签名需要触摸
- 保存配置并退出:
1
gpg/card> quit
第二步:将 GPG 子密钥迁移到 YubiKey
列出你的密钥并记录指纹:
1
gpg --list-secret-keys --keyid-format=long
在输出中找到你的主密钥 ID (例如
3DA13E2330595E7C),记下其完整指纹。编辑你的主密钥:
1
gpg --expert --edit-key <你的Key ID>
选择并迁移子密钥:
签名子密钥:1
2
3gpg> key 1 # 选择第一个子密钥(签名密钥)
gpg> keytocard
# 选择 1: Signature key加密子密钥:
1
2
3gpg> key 2 # 选择第二个子密钥(加密密钥)
gpg> keytocard
# 选择 2: Encryption key认证子密钥(用于 SSH):
1
2
3gpg> key 3 # 选择第三个子密钥(认证密钥)
gpg> keytocard
# 选择 3: Authentication key保存并退出:
1
gpg> save
第三步:验证迁移并配置环境
验证迁移结果:
运行gpg --card-status命令查看,你应该能看到三个插槽(Sig, Enc, Aut)都已显示出对应的密钥指纹。再运行gpg --list-secret-keys,被迁移的子密钥旁边会出现一个>符号,表示它们现在存储在YubiKey上。配置 Git 使用 YubiKey:
迁移完成后,你的签名命令git commit -S将会触发系统弹窗并要求你触摸 YubiKey,配置方式与你之前的完全相同。如果遇到问题,可以尝试重启gpg-agent:1
gpgconf --kill gpg-agent
⚠️ 重要的提醒:安全备份与恢复
私钥迁移到硬件后,你不能再把它提取出来。因此,备份是保障你数字身份永远不丢失的关键步骤。
- 准备第二把硬件钥匙:强烈建议购买两个硬件密钥,将一个作为备用。在第一步迁移子密钥时,依次对两把钥匙执行相同的操作。请务必将它们存放在不同的安全位置,例如一个随身携带,另一个锁在保险柜中,以避免单点故障。
- 妥善保管主密钥备份文件:你之前导出的加密主密钥备份文件(
master-key-backup.asc和subkeys-backup.asc),此时正静静地躺在你的安全离线存储设备中。
📌 最后,几个小点
- PIN码 ≠ 密码:
YubiKey的 PIN 码和gpg-agent的密码是两个不同的东西。 - 安全移除:使用完后直接拔掉就行。
- 跨平台:
YubiKey在 Windows, macOS, Linux 下都能工作。
对于普通开发者来说,把GPG密钥放在YubiKey上确实是最可靠的保护方式。它可以让你的Git提交签名无法被远程窃取和冒用,私钥也需要物理设备配合PIN才能使用,这种模式已经将安全性提到了一个很高的程度。
十六 大型文件加密与签名
对于极大型文件(例如几十GB的数据库备份或虚拟机镜像),直接使用 GPG 加密可能遇到内存压力、压缩效率低下或单文件操作不便等问题。你提到的几种方式正是解决这些问题的常用技巧。
下面依次解释 GPG 压缩行为、--compress-algo 与 split 的配合,以及 gpg --symmetric + tar 的专业做法。
一、GPG 默认压缩行为
GPG 在加密前会先对数据进行压缩(除非你使用 --compress-algo none)。默认压缩算法通常是 ZIP(或 ZLIB)。这对普通文件很有好处:
- 减少密文体积
- 增加破解难度(压缩破坏了已知明文模式)
但对极大型文件(尤其是已被压缩的视频、数据库备份),压缩可能:
- 浪费大量 CPU 时间
- 需要大量临时内存
- 几乎不减小体积
因此,处理数 GB 以上的文件时,建议:
1 | # 关闭压缩(推荐用于已压缩或难以压缩的大文件) |
二、--compress-algo 配合 split 分卷
当文件大到无法一次处理(例如超过磁盘剩余空间),可以先分割再分别加密,或者加密后分割。
方法 A:先分割后加密(推荐用于超大单文件)
1 | # 将 50GB 的 backup.iso 分割为每块 2GB |
解密时:
1 | # 解密每个分块 |
方法 B:加密后再分割(适合传输受限场景)
1 | # 先加密整体 |
接收方先合并再解密:
1 | cat backup.gpg.part.* > backup.iso.gpg |
--compress-algo none 可以防止 GPG 在加密大文件时尝试压缩(省时省内存)。如果你确定原始数据已经很难压缩(如视频、图片、已压缩的 tar),请务必加上。
三、更专业的做法:gpg --symmetric + tar
这是处理大量小文件或目录树的经典组合。tar 负责归档,gpg 负责加密,可以充分利用管道流,避免落盘中间文件。
基本用法(对称加密)
1 | # 将当前目录打包并加密,输出 result.tar.gz.gpg |
tar czvpf -:-表示输出到标准输出gpg --symmetric:从标准输入读取,加密后写入输出文件--compress-algo none:因为 tar 已经用了z(gzip 压缩),GPG 再次压缩收益极小,可以关闭
解密并解包
1 | gpg --decrypt 归档.tar.gz.gpg | tar xzvf - |
这样无需中间明文文件,直接流式处理,非常适合备份脚本。
进阶:使用公钥加密(非对称)
1 | tar czf - 重要文档/ | gpg --encrypt --recipient <接收者邮箱> --compress-algo none -o 重要文档.tar.gz.gpg |
解密时:
1 | gpg --decrypt 重要文档.tar.gz.gpg | tar xzf - |
四、大文件加密的性能建议
| 场景 | 推荐命令 | 理由 |
|---|---|---|
单个已压缩的大文件(如.zip, .mp4, .iso) |
gpg --compress-algo none --symmetric |
避免浪费 CPU 重新压缩 |
| 超大单文件 + 传输限制(邮件附件、网盘分块) | 先split 分块,再分别加密 |
便于传输,每块可独立解密 |
| 大量小文件(如代码仓库、文档目录) | `tar | gpg` 管道 |
| 需要长期归档 + 多个接收者 | tar → gpg --encrypt --recipient |
每个接收者用自己的公钥加密同一份数据 |
| 极大型(>50GB)+ 内存受限 | 先split 分块,每块单独加密 |
避免一次性读入整个文件到内存 |
五、--compress-algo 选项详解
1 | gpg --compress-algo {none|zip|zlib|bzip2} |
none:完全不压缩(适合已压缩或超大文件)zip:默认算法,速度和压缩比均衡zlib:与 zip 类似,兼容性好bzip2:压缩比更高但更慢
与 --symmetric 或 --encrypt 一起使用:
1 | gpg --compress-algo bzip2 --symmetric 大文件.db # 高压缩比,但非常慢 |
如果你用了 tar 自己的压缩(-z 或 -j 或 -J),强烈建议给 GPG 加 --compress-algo none,避免双重压缩浪费时间。
六、完整示例:备份 /home/user/Documents 到加密存档
1 | # 归档 + 压缩(tar 用 pigz 并行加速)+ GPG 对称加密(不压缩) |
解密:
1 | gpg --decrypt Documents.tar.gz.gpg | tar -I pigz -xf - |
-I pigz:用 pigz 多线程 gzip 压缩,速度更快(需安装 pigz)--cipher-algo AES256:指定强加密算法,比默认的 CAST5 更安全
七、总结
| 技术 | 适用场景 | 优点 |
|---|---|---|
split + gpg |
极大单文件(>10GB) | 分卷传输、内存友好 |
| `tar | gpg` | 目录/多文件 |
--compress-algo none |
已压缩/超大文件 | 省时省 CPU |
--symmetric |
自己或团队共享密码 | 简单、无需管理公钥 |
“更专业的做法” 之所以专业,是因为它结合了 Unix 管道哲学:tar 负责归档(和可选压缩),gpg 负责加密,两者解耦,可灵活替换压缩算法或加密方式,且完全避免落盘,适合自动化脚本和大型备份任务。
十七 更多加密算法
现代 GPG 推荐:Ed25519 / Curve 25519 椭圆曲线密钥
传统的 RSA 密钥(2048/4096 位)虽然广泛使用,但存在密钥较长、生成慢、签名/解密性能较低的缺点。现代 GPG (>=2.1) 全面支持基于椭圆曲线的 Ed25519 签名算法和 Curve 25519 加密算法,它们具有:
- 更短的密钥:公钥仅 32 字节(RSA 4096 位为 512 字节)
- 更强的安全性:~128 比特安全强度(相当于 RSA 3072)
- 更快的速度:生成、签名、验证均比 RSA 快数倍
- 更小的签名:签名长度固定 64 字节
- 现代标准:被 OpenSSH、TLS 1.3、Signal 等广泛采用
一、生成 Ed25519 主密钥(仅用于签名和认证)
使用 --full-generate-key 并选择 ECC 选项:
1 | gpg --full-generate-key |
交互步骤(注意:不同 GPG 版本菜单项编号可能略有差异,请以屏幕显示为准):
选择密钥类型:
(9) ECC (sign only) 或 (10) ECC (sign and encrypt)→ 推荐(9) ECC (sign only)生成主密钥(仅用于签名/认证),然后添加独立的加密子密钥。实际上 GPG 中
(9)对应ECC (sign only),(10)对应ECC (set your own capabilities)。但为了最简单的教学,可以选(10)并手动开启加密功能。更常见的推荐是:先生成仅签名的主密钥,再添加加密子密钥。选择椭圆曲线:
(1) Curve 25519
→ 输入1回车设置有效期:
0(永不过期)或1y/2y等输入用户 ID:姓名和邮箱
设置密码(passphrase)
生成后,你会得到一个 Ed25519 主密钥,其 Key ID 是类似 ED25519/ 开头的长串。
二、为什么推荐“仅签名主密钥 + 独立加密子密钥”?
- 安全分离:日常加密使用子密钥,主密钥可离线保存。
- 灵活撤销:如果加密子密钥泄露,只需吊销子密钥,无需更换主密钥(避免影响已有签名)。
- 符合最佳实践:GPG 默认架构就是主密钥 + 子密钥。
实际操作:生成主密钥后,添加加密子密钥:
1 | gpg --edit-key <你的Key ID> |
选择 (10) ECC (encrypt only) → 曲线选 Curve 25519 → 设置有效期 → 保存。
最终密钥结构:
1 | sec ed25519/xxxxxxxx 2025-01-01 [SC] # 主密钥(签名+认证) |
三、Ed25519 密钥的日常使用注意事项
✅ 优点体验
- 生成几乎瞬间完成(比 RSA 4096 快一个数量级)。
- 签名提交(
git commit -S)和验证非常快。 - 导出公钥(
gpg --export --armor)只有几行,便于分享。
⚠️ 兼容性问题
- 旧版 GPG (<2.1) 不支持 Ed25519。如果你的同事使用 CentOS 7 等旧系统,可能无法验证你的签名。
- 某些平台(如 GitLab 旧版本)虽支持 GPG,但可能未更新 Ed25519 解析库。现代主流平台(GitHub、GitLab 最新版)均已支持。
- 解决方法:如果必须兼容旧系统,可以同时生成一个 RSA 子密钥用于加密,或保留一个 RSA 备用密钥。
🔐 安全性说明
- Ed25519 签名是确定性的(无随机数依赖),避免了因随机数生成器缺陷导致私钥泄露的风险。
- Curve 25519 在设计上侧信道攻击抵抗力更强。
四、配置 Git 使用 Ed25519 密钥
与 RSA 密钥完全相同:
1 | git config --global user.signingkey <你的Key ID> |
GitHub 添加公钥时,同样粘贴 gpg --export --armor <Key ID> 输出的内容,平台会自动识别为 Ed25519。
五、迁移现有 RSA 密钥到 Ed25519
如果你已有 RSA 密钥,推荐新生成 Ed25519 密钥对,而非转换(椭圆曲线与 RSA 无法直接转换)。然后将新公钥添加到 GitHub,同时保留旧密钥一段时间,逐步过渡。
撤销旧密钥的方法:
- 生成旧密钥的撤销证书,导入并上传到密钥服务器。
- 或者简单地在 GitHub 上删除旧公钥(不影响已签名提交的验证)。
六、验证 Ed25519 是否生效
1 | gpg --list-keys --keyid-format=long |
输出中 sec 行会显示 ed25519/ 而不是 rsa4096/。
签名测试:
1 | echo "test" | gpg --clear-sign -u <Key ID> | gpg --verify |
Git 提交测试:
1 | git commit --allow-empty -m "test ed25519 signature" |
七、总结
| 特性 | RSA 4096 | Ed25519 |
|---|---|---|
| 公钥长度 | ~512 字节 | 32 字节 |
| 签名速度 | 较慢 | 快 5~10 倍 |
| 安全性 | ~128 bits | ~128 bits |
| 兼容性 | 所有 GPG 版本 | GPG >=2.1 |
| 推荐场景 | 兼容旧系统 | 新项目、日常开发 |
现代开发环境(Windows 10+、macOS 10.15+、主流 Linux 发行版)都已支持 Ed25519,建议新密钥优先使用它。如果你主要与个人项目或现代平台交互,可以放心选用。


.webp)

