一、GPG入门
GPG 全称 GnuPG,是一个命令行工具,于 1999 年由德国开发者 Werner Koch 向公众发布。它是 OpenPGP 标准的一个开源实现。
GPG 工具并不容易上手,主密钥与子秘钥的关系、信任网的工作原理都很抽象,一定要上手实践。
1、安装 GPG
macOS 的用户最好通过 Homebrew 安装 GPG:
brew install gpg大多数 Linux 的发行版内置 GPG,开箱即用。Debian 和 Ubuntu 的系统安装 GPG:
sudo apt install gpg安装完毕,gpg --help 查看命令, gpg --version 查看版本,我的版本信息如下,需要注意的是,不同版本加密算法的选项稍有不同,不过总体操作流程是一致的。
版本信息
gpg --version
gpg (GnuPG) 2.2.43
libgcrypt 1.10.3
Copyright (C) 2023 g10 Code GmbH
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /home/xkj/.gnupg
支持的算法:
公钥: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
密文: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
散列: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
压缩: 不压缩, ZIP, ZLIB, BZIP22、生成秘钥
生成秘钥的命令有 :
--full-generate-key(简写--full-gen-key)--generate-key(简写--gen-key)--quick-generate-key(不常用)
其中 --gen-key 和 --quick-generate-key 在加密算法、秘钥长度、有效期等选项使用默认值,而 --full-gen-key 则是由用户手动配置,考虑到以学习为目的,我们走最长路径。
gpg --full-gen-key选择加密算法及用途。选择默认值
(1) RSA and RSA (default),RSA 算法最常用,兼容性好。选择秘钥长度,1024~4096 位,默认 3072。位数越长,抵抗暴力攻击的安全性越高,相对加解密的开销越大,推荐设置最大值。
配置合适的有效期限,有效期限后面可重新设置。
3y、3m、3w、3分别对应三年、三个月、三个周和三天,0为永不过期。输入“姓名”、“邮箱”和“注释”,每一项都为非必填项,但“姓名”和“邮箱”至少保证其中一项有值。
确认信息,输入密码口令,再次确认密码,生成秘钥需要一会儿时间,期间可以胡乱移动鼠标或者敲打键盘,这会让随机数生成器获得足够的熵数。
密钥生成过程
gpg --full-gen-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory '/home/alice/.gnupg' created
gpg: keybox '/home/alice/.gnupg/pubring.kbx' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 3y
Key expires at Sun 13 Jul 2025 06:45:55 BST
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: alice
Email address: alice@example.com
Comment: Alice key for learning
You selected this USER-ID:
"alice (Alice key for learning) <alice@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/alice/.gnupg/trustdb.gpg: trustdb created
gpg: key D2E9A1DE3E6050E7 marked as ultimately trusted
gpg: directory '/home/alice/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/alice/.gnupg/openpgp-revocs.d/45571605D9D46583891EE269D2E9A1DE3E6050E7.rev'
public and secret key created and signed.
pub rsa4096 2022-07-14 [SC] [expires: 2025-07-13]
45571605D9D46583891EE269D2E9A1DE3E6050E7
uid alice (Alice key for learning) <alice@example.com>
sub rsa4096 2022-07-14 [E] [expires: 2025-07-13]gpg --full-gen-key
gpg (GnuPG) 2.2.43; Copyright (C) 2023 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
请选择您要使用的密钥类型:
(1) RSA 和 RSA (默认)
(2) DSA 和 Elgamal
(3) DSA(仅用于签名)
(4) RSA(仅用于签名)
(14)卡中现有密钥
您的选择是? 1
RSA 密钥的长度应在 1024 位与 4096 位之间。
您想要使用的密钥长度?(3072) 4096
请求的密钥长度是 4096 位
请设定这个密钥的有效期限。
0 = 密钥永不过期
<n> = 密钥在 n 天后过期
<n>w = 密钥在 n 周后过期
<n>m = 密钥在 n 月后过期
<n>y = 密钥在 n 年后过期
密钥的有效期限是?(0) 3y
密钥于 2027年08月07日 星期六 12时42分59秒 CST 过期
这些内容正确吗? (y/N) y
GnuPG 需要构建用户标识以辨认您的密钥。
真实姓名: test
姓名至少要有五个字符长
真实姓名: tests
电子邮件地址: tests@example.com
注释:
您选定了此用户标识:
“tests <tests@example.com>”
更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? o
我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘
、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数
发生器有更好的机会获得足够的熵。
我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘
、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数
发生器有更好的机会获得足够的熵。
gpg: 吊销证书已被存储为‘/home/xkj/.gnupg/openpgp-revocs.d/B4DFCA352C449DC7E4E5A4B9C66200D194975E48.rev’
公钥和私钥已经生成并被签名。
pub rsa4096 2024-08-07 [SC] [有效至:2027-08-07]
B4DFCA352C449DC7E4E5A4B9C66200D194975E48
uid tests <tests@example.com>
sub rsa4096 2024-08-07 [E] [有效至:2027-08-07]列出钥匙串上所有公钥 gpg --list-keys,短命令 gpg -k 等效。
gpg --list-keys
/home/alice/.gnupg/pubring.kbx
------------------------------
pub rsa4096 2022-07-14 [SC] [expires: 2025-07-13]
45571605D9D46583891EE269D2E9A1DE3E6050E7
uid [ultimate] alice (Alice key for learning) <alice@example.com>
sub rsa4096 2022-07-14 [E] [expires: 2025-07-13]列出所有私钥 --list-secret-keys,短命令 gpg -K。
gpg --list-secret-keys
gpg: 正在检查信任度数据库
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: 深度:0 有效性: 2 已签名: 0 信任度:0-,0q,0n,0m,0f,2u
gpg: 下次信任度数据库检查将于 2027-08-07 进行
/home/xkj/.gnupg/pubring.kbx
----------------------------
sec rsa4096 2024-08-07 [SC] [有效至:2027-08-07]
B4DFCA352C449DC7E4E5A4B9C66200D194975E48
uid [ 绝对 ] tests <tests@example.com>
ssb rsa4096 2024-08-07 [E] [有效至:2027-08-07]按照上面的步骤,我们得到一主密钥对(Primary keypair)和一子秘钥对(Subordinate keypair),而秘钥对是由公钥和私钥组成的。
pub-- public primary keysec-- secret primary keysub-- public sub-keyssb-- secret sub-key
rsa4096 代表秘钥算法和秘钥长度,接着是创建日期、秘钥功能、和有效期限。其中秘钥功能的含义如下:
45571605D9D46583891EE269D2E9A1DE3E6050E7 为公钥的指纹(fingerprint,又叫哈希值),后 16 位将会作为主密钥的 ID。以 uid 开头的一行是用户信息,包含有效性、用户名、备注、邮箱。最后一行是具有加密功能的子秘钥。

3、主密钥、子秘钥的操作
编辑秘钥命令:--edit-key。所有和秘钥相关的设置,都通过该命令完成,比如:
添加、吊销、删除子秘钥;
修改主密钥、子秘钥过期时间;
显示秘钥指纹(fingerprint),认证导入的公钥;
设置算法偏好、变更密码;
新增用户标识(uid 信息);
启用/禁用秘钥、变更信任度等等。
输入 gpg --edit-key alice@example.com,进入秘钥交互状态。交互状态下输入 help 查看所有命令。
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate # 信任度 有效性
ssb rsa4096/103FCD7E12E2082B # 算法 秘钥长度/子秘钥 ID
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com> # 用户 uid 信息
gpg> help3.1、添加子秘钥
现在,我们得到的秘钥为:具有 [SC] 功能的主密钥和一具有 [E] 功能的子秘钥。但现实的应用场景是复杂的,假设我们想使用其他子秘钥加密某些特定文件,那就得添加新的子秘钥了。
添加子秘钥使用 addkey 命令,与创建初始秘钥的过程相似,选择秘钥用途、秘钥长度、有效期限、最后输入密码即可,最后记得 save 保存。
添加子秘钥
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(14) Existing key from card
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: never usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> save3.2、修改秘钥有效期限
交互模式下输入 expire,修改主密钥的有效期。如修改某个子秘钥的有效期,先 key [n] 命令选中对应秘钥(选中和取消选中秘钥的命令都是 key [n]),再用 expire 命令,输入有效期限即可。
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: never usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> key 2
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb* rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: never usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> expire
Changing expiration time for a subkey.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 3y
Key expires at Sun 13 Jul 2025 06:56:32 BST
Is this correct? (y/N) y
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb* rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> save3.3、吊销子秘钥
使用秘钥的过程中,可能会遇到秘钥废弃、过期或者泄露的情形,这时需要立即吊销秘钥。秘钥一旦吊销,信息发送者便无法用该秘钥的公钥来加密信息,而信息的接受者依然可以使用该秘钥解密在此之前收到的信息。
进入交互模式,吊销整个秘钥,直接使用 revkey 命令。吊销子秘钥,先 key [n] 选中对应子秘钥,再运行 revkey 。
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2025-07-13
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> key 2
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
ssb* rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> revkey
Do you really want to revoke this subkey? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
Your decision? 0
Enter an optional description; end it with an empty line:
>
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
The following key was revoked on 2022-07-14 by RSA key D2E9A1DE3E6050E7 alice (Alice key for learning) <alice@example.com>
ssb rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 revoked: 2022-07-14 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> save3.4、删除子秘钥
删除秘钥属于危险操作,删除意味着之前使用该秘钥加密的所有信息将无法解密,删除前请确认秘钥已彻底废弃。
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
The following key was revoked on 2022-07-14 by RSA key D2E9A1DE3E6050E7 alice (Alice key for learning) <alice@example.com>
ssb rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 revoked: 2022-07-14 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> key 2
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
The following key was revoked on 2022-07-14 by RSA key D2E9A1DE3E6050E7 alice (Alice key for learning) <alice@example.com>
ssb* rsa4096/C9A9A1E7A477FEE6
created: 2022-07-14 revoked: 2022-07-14 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> delkey
Do you really want to delete this key? (y/N) y
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> save4、如何进行加密通信
假设 Alice 约 Bobby 吃火锅,为了防止信息被窃听,二人使用加密通信,那么具体需要哪些步骤呢?
AliceBobby加密通信Bobby,下午三点一起吃火锅,怎么样?OK!AliceBobby
双方交换秘钥;
Alice 用 Bobby 的公钥将明文(Bobby,下午三点一起吃火锅,怎么样?)加密,发送给 Bobby;
Bobby 用自己的私钥解密,将密文还原为明文;
Bobby 使用 Alice 的公钥将明文(OK!)加密,发送给 Alice;
Alice 用自己的私钥解密,将密文还原为明文。
在正式开始交换秘钥前,先完成准备工作:为了模拟两个人通信,我们可以新建一个系统用户,useradd -m bobby,同时开两个终端,其中一个登录 Alice,另一个登录 Bobby,接下来就可以左右手互搏了。
# 为 Bobby 生成秘钥
gpg --full-gen-key
# 查看秘钥列表
gpg -k
/home/bobby/.gnupg/pubring.kbx
------------------------------
pub rsa4096 2022-07-14 [SC] [expires: 2025-07-13]
E630E139264BB08B62EC62939D35E01249C1450D
uid [ultimate] bobby (Bobby key) <bobby@example.com>
sub rsa4096 2022-07-14 [E] [expires: 2025-07-13]4.1、交换秘钥
交换秘钥的第一步先要导出秘钥,--export 命令后的参数可以是 uid,也可以是用户邮箱地址,或者其中的一部分
Bobby 导出秘钥
# 二进制文件
gpg --output bobby.gpg --export bobby
# 纯文本文件
# gpg --output bobby.asc --armor --export bobbyAlice 导出秘钥
#二进制文件
gpg --output alice.gpg --export alice
# 纯文本文件
# gpg --output alice.asc --armor --export alice与私钥不同,公钥是公开的,不用担心被窃取。 bobby.gpg 为 Bobby 的公钥,Bobby 可通过当面交换 U 盘或者发送文件等方式,将该文件送到 Alice 手中。也可以通过 --armor 选项生成一串经过 ASCII 编码的纯文本,通过邮件或者即时通讯工具发送纯文本给对方。
以 Alice 为例,拿到对方公钥后,首先导入秘钥,再对秘钥的指纹(fingerprint)进行验证,通过电话向 Bobby 确认指纹是否一致,如果一致,则证明文件在传递的过程中没有被篡改。最后使用 sign 命令签署。
Alice 导入 Bobby 的公钥
gpg --import bobby.asc
# 查看钥匙串
gpg --list-keys
/home/alice/.gnupg/pubring.kbx
------------------------------
pub rsa4096 2022-07-14 [SC] [expires: 2025-07-13]
45571605D9D46583891EE269D2E9A1DE3E6050E7
uid [ultimate] alice (Alice key for learning) <alice@example.com>
sub rsa4096 2022-07-14 [E] [expires: 2025-07-13]
pub rsa4096 2022-07-14 [SC] [expires: 2025-07-13]
E630E139264BB08B62EC62939D35E01249C1450D
uid [ unknown] bobby (Bobby key) <bobby@example.com>
sub rsa4096 2022-07-14 [E] [expires: 2025-07-13]Bobby 导入、签署认证 Alice 公钥的流程也是一样的。
4.2、加密信息与解密信息
双方秘钥认证完毕,就可以发送加密信息了,以 Alice 发送信息为例:
Alice 使用 Bobby 的公钥对文件加密;
Alice 将密文传递给 Bobby;
Bobby 接收到加密文件后,用自己的私钥解密。

# 明文文件
echo "Bobby,下午三点一起吃火锅,怎么样?" > msg
# 生成二进制加密文件
gpg --output msg.gpg --encrypt --recipient bobby msg
# 简化命令
# gpg -o msg.gpg -er bobby msg
# 或者生成纯文本加密文件
# gpg --output msg.asc --armor --encrypt --recipient bobby msg
# 简化命令
# gpg -o msg.asc -ear bobby msgBobby 解密信息的过程

gpg --decrypt msg.gpg
# 简化命令
# gpg -d msg.gpg
# 通过 --output 输出到文件
# gpg --output msg.txt --decrypt msg.gpg4.3、文件签名和验证
与文件加密不同,文件签名时,发送者需要用自己的私钥对文件签名,接受者使用发送者的公钥对文件进行验证。
Alice 对文件 doc 签名,sign 命令会对文档签名并压缩,生成二进制文件签名:
# 生成需要签名的文件
echo "Hello world, Alice signature" > doc
gpg --output doc.sig --sign docBobby 验证 Alice 的签名,检查签名并提取文档:
gpg --output doc-from-alice --decrypt doc.sig有时候我们需要在电子邮件上签名,或者在网络帖子上签名。此时签名时压缩文档是不可取的。使用选项 --clearsign 会将文档包装为 ASCII 纯文本签名。
创建纯文本签名
gpg --output doc.asc --clearsign docBobby 验证签名
gpg --decrypt doc.asc上面的两种签名方式用处有限,因为接收者必须从已签名的版本中恢复原始文件,这里推荐第三种签名方式——使用--detach-sign命令,创建分离的签名——更常用一些。
创建分离的签名
gpg --output doc.sig --detach-sign docBobby 验证签名
gpg --verify doc.sig doc4.4、对称加密
如果只是简单地将文件加密保存,对称加密是一个很好的选择。使用下面命令,输入口令后会生成加密过的文件,注意:这里不要使用和主密钥一样的口令。
gpg --output doc.gpg --symmetric doc5、如何发布 PGP 公钥?
每个人加密的需求不同,所以用什么样的方式发布公钥,请根据自身情况来定。
5.1、通过 KeyServer 发布、吊销公钥
KeyServer 是专门用于收集和分发公钥的服务器,它的出现在一定程度上简化了人们分发秘钥的流程。用户将自己的公钥上传到公钥服务器,其他人在服务器上搜索 uid 或者 keyid ,就可以快速导入公钥。但是请注意,公钥一旦上传到服务器,是无法删除的,只能吊销,而且,生成秘钥时的用户名和邮箱地址都是公开的,任何人都能看见,所以建议使用伪邮箱地址来练习。更多关于 KeyServer 的内容推荐阅读 《2021 年,用更现代的方法使用 PGP》
以 ubuntu keyserver 为例,将本地公钥推送到远程服务器:
gpg --keyserver hkps://keyserver.ubuntu.com --send-key [PRIMARYKEYID]搜索服务器中的公钥,搜索得出结果后,输入索引数字,导入公钥:
gpg --keyserver hkps://keyserver.ubuntu.com --search-keys [PRIMARYKEYID/UID]直接导入 ID 为指定值的公钥:
gpg --keyserver hkps://keyserver.ubuntu.com --receive-keys [PRIMARYKEYID]生成吊销证书
gpg --output revoke.asc --gen-revoke alice吊销本地秘钥
gpg --import revoke.asc吊销信息同步服务器,吊销后 https://keyserver.ubuntu.com/ 能看到红色 revok 标记
gpg --keyserver hkps://keyserver.ubuntu.com --send-key [YOURPRIMARYKEYID]5.2、信任网(web of trust)
使用 GPG 时,确认自己得到的公钥是否真的属于正确的人(即公钥合法性)非常重要,因为公钥可能会通过 中间人攻击 被替换。
为了证明公钥确实属于某个人,常规的做法是引入认证机构,由认证机构担保公钥的合法性,类似 https 证书的机制。Bobby 向认证机构注册自己的公钥,认证机构确认 Bobby 身份与公钥的一致性后,由认证机构对公钥签名,为 Bobby 的公钥合法性背书。当 Alice 要给 Bobby 发送加密信息时,Alice 从认证机构下载 Bobby 的公钥即可。
然而 GPG 并没有采用这种机制,而是采用了一种叫信任网的方法,在这种方法中,GPG 用户互相为对方的公钥进行签名认证。信任网的要点是不依赖认证机构,从而建立每个人之间的信任关系,就是自己去决定要信任哪些公钥。
使用命令 --edit-key ,能看到两个属性,一个是 trust,另一个为 validity(有效性)。trust 代表信任度,信任度是一种主观选择,一共有五个信任级别。
1 = I don't know or won't say (我不知道或不作答)
2 = I do NOT trust(我不相信)
3 = I trust marginally(我勉强相信)
4 = I trust fully(我完全相信)
5 = I trust ultimately(我绝对相信)修改信任度
gpg --edit-key bobby@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pub rsa4096/9D35E01249C1450D
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: unknown validity: full
sub rsa4096/DA3FED6077F7F30D
created: 2022-07-14 expires: 2025-07-13 usage: E
[ full ] (1). bobby (Bobby key) <bobby@example.com>
gpg> trust
pub rsa4096/9D35E01249C1450D
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: unknown validity: full
sub rsa4096/DA3FED6077F7F30D
created: 2022-07-14 expires: 2025-07-13 usage: E
[ full ] (1). bobby (Bobby key) <bobby@example.com>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 2
pub rsa4096/9D35E01249C1450D
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: never validity: full
sub rsa4096/DA3FED6077F7F30D
created: 2022-07-14 expires: 2025-07-13 usage: E
[ full ] (1). bobby (Bobby key) <bobby@example.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
gpg> save
Key not changed so no update needed.
箭头代表签署关系,Alice 签署了 Bobby 的公钥,Bobby 的公钥对 Alice 是有效的,但 Alice 可以选择不信任 Bobby 正确验证并签署的公钥。这种情况下,仅凭 Bobby 的签名,Alice 是不会认为 Chloe 的公钥是有效的。
最初,公钥在你签名后才被视为有效,而现在可以使用更灵活的算法,如果公钥同时满足了两个条件则视为有效:
它有足够多的有效签名,比如
本人为公钥添加签名,
或者被一个完全信任的人签名,
或者被三个有限信任的人签名。
秘钥到本人的路径最大为 5 步或者更短。
有限信任人签署的个数,和最大路径长度是可以设置的。下面假设需要两个有限信任密钥或一个完全受信任密钥来验证另一个密钥,且最大路径长度为 3。在计算示例中的有效密钥时,Bobby 和 Dharma 的密钥始终被认为是完全有效的,因为它们是由 Alice 直接签名的。假设 Dharma 是完全信任的,那么由他签署的 Chloe 和 Francis 的秘钥将被视为有效。再假设 Bobby 和 Dharma 都是有限信任的,根据两个有限信任的人签署后认为有效,那么 Chloe 的秘钥将被视为有效,而 Francis 的秘钥视为勉强有效。

信任网的工作机制,有点像生活中的“熟人圈子”。好比 A 信任 B,B 信任 C,所以 A 也信任 C。信任并不能凭空产生,而是基于现有信任之上。
5.3、其他秘钥发布方式
当面交换
使用邮箱或者其他即时通讯工具
发布于个人网站或社交网络
代码仓库
6、其他
6.1、新增 UID
根据 GPG 官方手册的描述,GPG 秘钥可以设置多个 uid。现实生活中,一个人可以有多种身份,每种身份可能对应不同的邮箱和用户名。
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 1 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1 valid: 1 signed: 0 trust: 0-, 0q, 1n, 0m, 0f, 0u
gpg: next trustdb check due at 2025-07-13
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1). alice (Alice key for learning) <alice@example.com>
gpg> adduid
Real name: alice.github
Email address: alice.github@example.com
Comment:
You selected this USER-ID:
"alice.github <alice.github@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
sec rsa4096/D2E9A1DE3E6050E7
created: 2022-07-14 expires: 2025-07-13 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/103FCD7E12E2082B
created: 2022-07-14 expires: 2025-07-13 usage: E
[ultimate] (1) alice (Alice key for learning) <alice@example.com>
[ unknown] (2). alice.github <alice.github@example.com>
gpg> save6.2、其他秘钥功能
查看子秘钥指纹:
gpg --list-keys --with-subkey-fingerprint使用特定子秘钥加密:
# -r 后面参数为 0x[subkey id]!,一定要有!
gpg --recipient 0x103FCD7E12E2082B! --encrypt doc
# 或者
gpg -er 0x103FCD7E12E2082B! doc使用特定子秘钥签名:假设用于签名的秘钥 id 为8FA3C48E0E9AF514
gpg --output doc.sig --local-user 0x8FA3C48E0E9AF514! --clearsign doc
# 短命令:
gpg -o doc.sig -u 0x8FA3C48E0E9AF514! --clearsign doc当接受方为多人,可同时用多个秘钥加密:
gpg -r alice -r bobby -e doc6.3、秘钥导出
使用 --export 命令导出全部公钥,其中包括 pub、所有 sub,全部 uid 信息。
导出钥匙串中全部公钥:
gpg --export > public-keys.gpg导出私钥,其中包括 pub、sec、sub、ssb 和全部 uid 信息:
gpg --export-secret-keys > private-keys.gpg导出子私钥,包括 pub、sub、ssb 和全部 uid 信息,无 sec:
gpg --export-secret-subkeys > private-subkeys.gpg上面的三个导出命令都可以加参数,参数为 UID/PRIMARYKEYID 时,按其筛选。
导出uid为alice的全部公钥:
gpg --export alice > alice-pub-keys.gpg参数为特定子秘钥的 id7D4DA3D8C798D51F,表示按子秘钥 id 筛选:
gpg --armor --export 0x7D4DA3D8C798D51F! > aaa.asc
gpg --armor --export-secret-keys 0x7D4DA3D8C798D51F! > bbb.asc
gpg --export-secret-subkeys 0x7D4DA3D8C798D51F! > ccc.asc最后导出信任数据:
gpg --export-ownertrust > ownertrust.asc以上就是 GPG 的基础知识和用法,关于秘钥的备份和导出策略在下一篇中 GPG 最佳实践 中叙述。
二、GPG最佳实践
1、创建职责分离主密钥与子秘钥

在 GPG 的架构中,
主密钥必须具有[C] 功能,可兼备[S]、[E]、[A]功能中的一项或多项,
子秘钥可具有[S]、[E]、[A]功能中的一项或多项。
为什么要创建职责分离的主密钥与子秘钥呢?
首先子秘钥是一个单独的秘钥对,与主密钥只是从属关系,在功能上是完全独立的,而且子秘钥可以独立于主密钥被吊销。
其次,主密钥非常重要。如果主密钥被盗,别人一旦获得了主密钥的控制权,就能用你的名义做任何事情,比如签署文件,解密信息等。而且吊销主密钥会带来巨大的成本损失——你需要重新建立信任。由于信任网的每个连接都是对主密钥和用户 ID 之间绑定的认可,与子秘钥无关(子秘钥的创建和吊销不会影响主密钥之间的信任关系)。所以,如果在主密钥安全的情况下子秘钥被盗,你只需吊销被盗的子秘钥,并签发新的子秘钥即可。
1.1、创建主密钥
gpg --expert --full-gen-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection? 8
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? e
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 3y
Key expires at Sun 23 Mar 2025 04:51:32 GMT
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: alice
Email address: alice@example.com
Comment:
You selected this USER-ID:
"alice <alice@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/alice/.gnupg/trustdb.gpg: trustdb created
gpg: key A39421B65EF4D2D7 marked as ultimately trusted
gpg: directory '/home/alice/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/alice/.gnupg/openpgp-revocs.d/C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7.rev'
public and secret key created and signed.
pub rsa4096 2022-03-24 [C] [expires: 2025-03-23]
C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7
uid alice <alice@example.com>1.2、创建加密功能的子密钥
gpg --expert --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa4096/A39421B65EF4D2D7
created: 2022-03-24 expires: 2025-03-23 usage: C
trust: ultimate validity: ultimate
[ultimate] (1). alice <alice@example.com>
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 3y
Key expires at Sun 23 Mar 2025 04:59:04 GMT
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa4096/A39421B65EF4D2D7
created: 2022-03-24 expires: 2025-03-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/18832C062E4EBE77
created: 2022-03-24 expires: 2025-03-23 usage: E
[ultimate] (1). alice <alice@example.com>
gpg> save秘钥创建完成后如下:
gpg --edit-key alice@example.com
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec rsa4096/A39421B65EF4D2D7
created: 2022-03-24 expires: 2025-03-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/18832C062E4EBE77
created: 2022-03-24 expires: 2025-03-23 usage: E
ssb rsa4096/EFE05191993439D6
created: 2022-03-24 expires: 2025-03-23 usage: S
ssb rsa4096/5B4D08C955707D10
created: 2022-03-24 expires: 2025-03-23 usage: A
[ultimate] (1). alice <alice@example.com>2、使用主密钥的场景
主密钥只具有[C]功能,只在以下情形时使用主密钥:
签署其他人密钥或撤销现有签名;
添加新身份信息或将现有 UID 标记为主 UID;
创建新子秘钥;
撤销现有 UID 或子密钥;
更改 UID 的首选项(例如,使用 setpref);
更改主密钥或其任何子秘钥的过期日期;
撤销或生成完整密钥的撤销证书。
3、备份方案
方案一:单独导出备份文件
# 备份步骤
# step 1: 导出秘钥信息,其中包括所有公钥,私钥,信任网数据库文件,进行备份
gpg --export > public-keys.gpg
gpg --export-secret-keys > private-keys.gpg
gpg --export-ownertrust > ownertrust.asc
# step 2: 导出秘钥吊销凭证,建议单独备份
gpg --armor --gen-revoke [primary key ID] > revocation.asc
# 恢复秘钥
# step 1: 导出公钥,私钥和信任网数据库
gpg --import pgp-public-keys.asc
gpg --import pgp-private-keys.asc
gpg --import-ownertrust pgp-ownertrust.asc
# 如果秘钥泄露,需要吊销秘钥
gpg --import pgp-revocation.asc方案二:全文件夹备份,加密保存
# 压缩目录,备份文件
tar -zcvf gnupg.tar.gz ~/.gnupg/*
# 恢复秘钥,解压文件
tar -zxvf gnupg.tar.gz个人喜欢方案二,只要保证备份和解压时的权限是安全的,后者更方便。特殊场合使用时插上 U 盘直接在 U 盘中对秘钥进行操作,由于不涉及到硬盘读写,自然不会在硬盘中留下痕迹。
4、主密钥离线使用
主密钥和子秘钥职责分离后,用到主密钥的场合非常少。需要主密钥执行某些操作时,插上 U 盘,保证环境权限安全的情况下,解压 gnupg.tar.gz,恢复秘钥即可。
使用时可通过设置环境变量的方式
export GNUPGHOME=/media/yourdrive/path/to/.gnupg
gpg -k或者使用 --homedir 参数。
gpg --homedir=/media/yourdrive/path/to/.gnupg -k而日常使用中,涉及到加密、签名和身份认证,使用子秘钥的场合会更多一些。这里的要点是让主密钥的私钥(secret primary key)离线,同时重设新密码来保护子秘钥。使用这种方式,就算新密码被泄露,主私钥(secret primary key)依然保持安全——备份的秘钥仍在旧密码的保护中且主私钥文件没有泄露。
# step 1:导出子私钥,公钥和信任信息
gpg --export-secret-subkeys > private-subkeys.gpg # 注意:是 --export-secret-subkeys 而不是 --export-secret-keys
gpg --export > public-keys.gpg
gpg --export-ownertrust > ownertrust.asc
# step 2: 重新恢复秘钥,目的是让 sec(secret primary key)离线
gpg --import private-subkeys.gpg
gpg --import public-keys.gpg
gpg --import-ownertrust ownertrust.asc
# step 3: 检查是否离线,以 sec 后面带有#为准
gpg -K
/home/alice/.gnupg/pubring.kbx
---------------------------
sec# rsa3072 2022-03-25 [SC]
C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D7
uid [ultimate] alice <alice@example.com>
ssb rsa3072 2022-03-25 [E]
# step 4: 修改密码,更换为新的密码
gpg --change-passphrase C105EE41AB5FDFAB2D00F2FFA39421B65EF4D2D75、保持更新公钥
定期更新公钥,及时同步对方公钥的过期、撤销信息,避免在对方已撤销公钥的情况下发送加密信息,务必确认公钥的有效性。
评论区