GnuPG 加密与签名速查表 - GPG 加密解密命令大全
GPG 的日常动作可以压成四个:生成密钥对、把公钥给对方、对方用你的公钥加密、你用私钥解密或签名。真正容易翻车的不是命令而是密钥本身——私钥丢了就无法恢复,所以生成后第一件事是导出备份;收到他人公钥也别直接信任,要核对指纹确认没有被中间人替换。本表按密钥生成与管理、导入导出、加密解密、签名验证、信任与密钥服务器、Git 签名与实用分组,把整条链路串起来。日常使用时还有两个习惯值得保持:用 -a 输出 ASCII armored 形式以便放进邮件或聊天窗口;用 gpg-agent 缓存密码,少输多次口令;给密钥加过期时间并定期轮换,比一次性设置永不过期更容易应对审计。
典型使用场景
面向需要「可验证的身份」而不是「信任某个人」的场景:给 Git 提交和 tag 签名、把发布包签名让人验证、把机密文件加密给同事、给自己签发密钥做备份。GnuPG 的失败原因往往很具体也很反直觉:gpg-agent 没起来时一切卡死、导入了公钥却忘了 trust 导致验证仍提示「未经签名」、密钥服务器上一个字符的邮箱输错就静默返回空结果。所以本表的重点不只是命令怎么写,而是每一步做完后**去哪儿看结果**。
密钥生成与管理 8
gpg --full-generate-keygpg --quick-generate-key "Name <email>"gpg --list-keysgpg --list-secret-keysgpg --list-keys KEYIDgpg --edit-key KEYIDgpg --delete-key KEYIDgpg --delete-secret-key KEYID密钥导入导出 6
gpg --export -a KEYID > pubkey.ascgpg --export-secret-keys -a KEYID > private.ascgpg --import pubkey.ascgpg --import private.ascgpg --send-keys KEYID --keyserver keyserver.ubuntu.comgpg --recv-keys KEYID加密与解密 6
gpg -e -r recipient@domain.com secret.txtgpg -e -r user@domain.com -o secret.txt.gpg secret.txtgpg -d secret.txt.gpg > secret.txtgpg -c secret.txtgpg -d secret.txt.gpgecho "message" | gpg -e -r user@domain.com签名与验证 6
gpg -s document.txtgpg --clear-sign document.txtgpg -b document.txtgpg --verify document.txt.sig document.txtgpg --verify document.txt.ascgpg --detach-sign -a file.tar.gz信任与密钥服务器 5
gpg --edit-key KEYID
> trustgpg --sign-key KEYIDgpg --refresh-keysgpg --search-keys "user@domain.com"gpg --fingerprint KEYIDGit 签名与实用 6
git config --global user.signingkey KEYIDgit config --global commit.gpgsign truegit commit -S -m "message"git tag -s v1.0 -m "release"git verify-commit HEADgpgconf --kill gpg-agent参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
--quick-generate-key | 非交互一条命令出密钥,适合脚本;无交互选项时用它代替 --full-generate-key | gpg --quick-generate-key "Name <email>" |
--recv-keys | 从密钥服务器拉取他人公钥;必须配 KEYID 或邮箱,邮箱拼错不会报错只是拉不到 | gpg --recv-keys KEYID |
--clear-sign | 生成明文签名,正文可读且内嵌签名,适合邮件与可读性优先的场景 | gpg --clear-sign document.txt |
commit.gpgsign | 让 git 每次提交自动 GPG 签名,验证方可追溯到密钥指纹 | git config --global commit.gpgsign true |
gpgconf --kill gpg-agent | 重启代理进程,解决改密码后不弹口令、旧口令一直有效的僵死状态 | gpgconf --kill gpg-agent |
易错点与避坑指南
现象gpg --import 后 gpg --verify 仍提示签名不是来自这个密钥,甚至出现 WARNING。
原因公钥导入了但没有建立信任,gpg 不知道该密钥是否可信。
处置先 gpg --fingerprint KEYID 核对指纹,再 gpg --edit-key KEYID 进入后 trust 设成 ultimate,退出后重新验证。
现象gpg --recv-keys 命令跑完没有任何输出,也没报错,但公钥并不在本地。
原因邮箱拼错或密钥服务器上根本没有对应密钥,收到的响应为空。
处置改用 gpg --search-keys "user@domain.com" 先搜到确切 KEYID/指纹,再 gpg --recv-keys。
现象改了私钥密码后 gpg 仍然只认旧密码,或操作长时间卡住不返回。
原因gpg-agent 缓存了旧的 passphrase 状态,进程僵死。
处置执行 gpgconf --kill gpg-agent 重启代理后再操作。
现象git commit -S 卡在终端里不返回,CI 上直接失败。
原因gpg 需要交互式输入口令,无 TTY 的环境(CI、定时任务)里必然挂住。
处置CI 中改用 gpg --batch --pinentry-mode loopback 配合 gpg-agent 缓存,并在提交前 gpgconf --kill gpg-agent 验证缓存可用。
现象导出的私钥文件随手提交进了仓库或发到了聊天工具。
原因gpg --export-secret-keys -a KEYID 输出的是可直接使用的私钥,泄露即失去全部身份。
处置立即 gpg --delete-secret-key KEYID 并吊销对应公钥,重新生成密钥对;私钥只进密码管理器或离线备份。
排障路径
1签名验证失败时,先核对指纹再看信任
gpg --fingerprint KEYID && gpg --verify document.txt.sig document.txt指纹必须与对方公开渠道公布的完全一致;一致但仍警告,说明是 trust 未设,不是密钥不对。
2按邮箱找密钥
gpg --search-keys "user@domain.com"拿到 KEYID 后用 gpg --recv-keys KEYID 精确拉取,比直接 recv 邮箱可靠。
3确认本机公私钥齐全
gpg --list-keys && gpg --list-secret-keys--list-keys 有而 --list-secret-keys 没有,说明私钥没导入或已被删除,签名会失败。
4代理状态异常时重置
gpgconf --kill gpg-agent口令缓存失效、改密码后不生效、gpg 卡死,都先用这条重置代理。
命令示例
非交互地生成一对新密钥
gpg --quick-generate-key "Name <email>"默认算法与子密钥已够日常签名和加密使用;生成后用 gpg --list-secret-keys 确认私钥在本地。
用收件人公钥加密并指定输出文件名
gpg -e -r user@domain.com -o secret.txt.gpg secret.txt加密只需要对方的公钥;对方用自己的私钥解密,公钥泄露不构成风险。
生成明文签名:正文可读且内嵌签名
gpg --clear-sign document.txt输出是 .asc 里的可读正文加签名,验证只需 gpg --verify document.txt.asc。
验证最近一次 Git 提交的签名
git verify-commit HEAD要签提交需先 gpg config 层面设置 signingkey 并开启 commit.gpgsign(用 git config --global),否则提交根本没有签名。
常见坑与注意事项
- 导出的私钥文件(private.asc 之类)绝不能进 Git 仓库或发到聊天工具,一旦泄露等于身份被完整克隆。
- 把信任等级设为 ultimate 之前必须线下核对指纹,trust 是在声明「我确认这把钥匙属于这个人」,不是随手点的按钮。
- 改过私钥密码后若仍只认旧密码或命令卡住,先 gpgconf --kill gpg-agent 重启代理,再排查别的原因。
- 签名有效不等于身份可信:gpg --verify 通过后仍要看 WARNING 与信任等级,必要时用 gpg --fingerprint 核对。
- 加密前先确认已导入对方公钥(gpg --recv-keys 后 gpg --list-keys 复查),缺公钥时不会报错,只是根本收不到。
提示
- Git commit 签名:git config --global commit.gpgsign true,配合 GPG 密钥使用。
- gpg --armor (-a) 可以生成 ASCII 格式的密钥或签名,方便文本传输。
- 密钥备份:导出私钥 gpg --export-secret-keys -a KEYID > private.asc,妥善保管。
- gpg-agent 可以缓存密码,避免每次解密都输入密码。
- gpgconf --kill gpg-agent 可以重启 agent,解决密码缓存异常问题。
- 密钥指纹是验证密钥真伪的重要方式,导入他人公钥后务必核对指纹。
- 生成时带 --quick-generate-key "姓名 <邮箱>" 少一堆交互,subkey 的默认算法已够日常签名与加密使用。
- gpg --list-keys --keyid-format LONG 显示完整 KEYID,撤销时用 --revoke 指定该 ID 比短指纹可靠。
- 导入他人公钥后先 gpg --fingerprint 查看,信任等级用 --edit-key 设为 ultimate 前务必线下核对指纹。
常见问题
gpg --verify 明明说签名有效,却还是提示签名不来自这个密钥?
签名有效只说明数据和签名对得上,不说明你对签名者建立了信任。先用 gpg --fingerprint KEYID 核对指纹是否与对方线下提供的一致,再用 gpg --edit-key KEYID 把信任等级设上去。指纹对不上就不要继续,那说明密钥不是同一个人生成的那一把。
gpg --recv-keys 跑完没输出也没报错,公钥却不在本地?
最常见的原因是标识写错了,邮箱差一个字符时命令不会报错,只是静默地什么也没拉到。先用 gpg --search-keys "user@domain.com" 在密钥服务器上搜一遍确认标识拼写,再把搜索结果里的 KEYID 传给 --recv-keys。导入后用 gpg --list-keys 确认它确实出现在公钥列表里。
对称加密和用对方公钥加密该怎么选?
用密码的 gpg -c 不需要任何公钥,适合随手加密一个文件,缺点是密码得自己 securely 保管和传递。用公钥的 gpg -e -r user@domain.com 适合发给固定的人,你只持有他的公钥,密码由他自己的私钥解锁,多个收件人可以各自用自己的密钥解开。
分离签名和明文签名验证方式有什么不同?
gpg -b 生成的是分离签名,原文件不动、签名单独落在 .sig,验证时要把两个文件一起给它:gpg --verify document.txt.sig document.txt。gpg --clear-sign 生成的是明文签名,签名内嵌在文件里,验证只需给这一个文件:gpg --verify document.txt.asc。选哪种取决于接收方更在意原文可读还是原文件不被改动。
改了私钥密码之后 GPG 仍然只认旧密码,或者操作一直卡住?
这是 gpg-agent 的缓存没刷新,它还拿着改密码之前的口令在内存里。执行 gpgconf --kill gpg-agent 重启代理进程,之后所有涉及私钥的操作都会重新走一遍口令校验。git commit -S 之类的命令在终端里卡住不动,也是同一个原因,签名前把 agent 重启掉即可。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。