目录

使用 GnuPG 创建密钥对

安全警告
文中出现的密钥对信息均为演示作用,请勿信任与本文信息相同的密钥!

安装与验证

GnuPG(下称 GPG)的安装根据操作系统与发行版的不同,步骤不尽相同,需要参考系统发行版的官方文档来进行安装。安装完成后,使用 gpg --version 来查看 GPG 的安装信息以及版本信息,以及后续所生成的密钥文件的存放位置(即输出信息中的 Home)。

$ gpg --version
gpg (GnuPG) 2.x.xx

...

Home: /home/<your_username>/.gnupg
支持的算法:
公钥: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
...
压缩:  不压缩, ZIP, ZLIB, BZIP2

生成第一对密钥

GPG 安装后,就可以使用以下命令来生成第一对公钥与密钥了:

$ gpg --full-generate-key

# interactive instructions
...

pub   rsa4096 2022-05-26 [SC]
      24C2C31B933B8CA63B5D538FE0772B35B2E02051
uid                      Sam Chu (Personal use only) <samchu-social@outlook.com>
sub   rsa4096 2022-05-26 [E]

接下来会在终端交互式的给出密钥生成的选项,需要依次对以下选项进行选择:

  • 密钥类型。目前已有研究表明,在密钥长度足够的情况下,各种类型的加密方式安全性相当,当然,这一结论未来可能会发生变化。一个好的加密软件会根据最新研究结果修改默认的加密方式,所以这里选择默认选项(RSA 和 RSA)即可。
  • 密钥长度。为了保证密钥未来的安全性,这里选择最大长度(4096)。
  • 密钥有效期限。一个好的密钥需要根据使用场景严格限定其有效期限,目前该密钥仅应用于个人信息加密,所以选择永不过期。
  • 真实姓名。这里可以填入自己常用的用户名,作为他人识别该密钥的标识。
  • 电子邮件。由于生成的公钥是公开的,所以这里需要填写常用的邮箱(如果有特殊用处,如 GitHub 认证提交,则需要使用对应邮箱)。
  • 注释:填入对该密钥的注释,方便后期对该密钥用处进行识别。

以上选项确定后,会要求对该密钥设置密码,后续进行密钥操作时都会用到,所以务必牢记该密码。最后 GPG 会提示你进行「敲打键盘、移动鼠标、读写硬盘之类的」其他操作以产生随机数。

生成好的密钥对会存放在 GPG 的 Home 目录(默认为 /home/<your_username>/.gnupg)下,同时还生成了一个吊销证书。吊销证书的作用是在你确认私钥已经泄露或丢失等情况下,帮助你可信地告知其他用户你的公钥已经失效。所以生成的私钥与吊销证书都必须保证安全,任何一个文件泄露都可能造成身份丢失。

密钥生成完毕后,会在终端上打印出生成的公钥信息。当然后续也可以通过以下命令查看已有的密钥。

$ gpg -k --keyid-format LONG
/home/<your_username>/.gnupg/pubring.kbx
----------------------------
pub   rsa4096/E0772B35B2E02051 2022-05-26 [SC]
      24C2C31B933B8CA63B5D538FE0772B35B2E02051
uid                   [ 绝对 ] Sam Chu (Personal use only) <samchu-social@outlook.com>
sub   rsa4096/E5B924315C3F59D1 2022-05-26 [E]

$ gpg -K --keyid-format LONG
/home/<your_username>/.gnupg/pubring.kbx
----------------------------
sec   rsa4096/E0772B35B2E02051 2022-05-26 [SC]
      24C2C31B933B8CA63B5D538FE0772B35B2E02051
uid                   [ 绝对 ] Sam Chu (Personal use only) <samchu-social@outlook.com>
ssb   rsa4096/E5B924315C3F59D1 2022-05-26 [E]

上面的命令中,-k/--list-public-keys 列出公钥信息,-K/--list-secret-keys 列出私钥信息,--keyid-format 设置打印密钥 ID 的格式。每次列出密钥信息时都需要加上 --keyid-format 选项比较麻烦,可以通过执行 echo "keyid-format LONG" > ~/.gnupg/gpg.conf 来将设置写进配置文件中。

在 GPG 打印出来的密钥信息中,pubsec 表示主密钥的公钥与私钥,而 subssb 表示子密钥的公钥与私钥。有关主密钥与子密钥的解释与应用场景请参阅 参考文章 中的文章。在 pubsecsubssb 行中显示的是密钥的加密方式、密钥 ID、生成时间以及密钥用途(E/S/C/A 分别表示加密/签名/子密钥认证/身份认证);下一行为密钥的指纹,通过 40 个十六进制数表示,指纹是密钥的唯一标识;uid 一行标识密钥的用户身份,以 [信任值] 姓名 (注释) <电子邮件> 显示,其中信任值用于表明对所有者的信任程度及密钥有效性,可能的值参见 gpg(1) - Arch manual pages

生成签名子密钥

在实际应用场景中,如果在多台设备上使用同一对密钥进行签名加密操作,一旦发生密钥泄露,则设备上所有的加密信息以及签名文件都会陷入被暴露的危险。此时除了撤销整个密钥没有其他办法。但是如果在不同机器上使用不同的子密钥进行加密或签名,就能够保证一个子密钥的泄露不会影响到其他子密钥的使用。而 GPG 支持一对主密钥与多个子密钥正是考虑到了这一点,在密钥对生成时就已经默认生成一对仅用于加密的子密钥。使用 gpg --edit-key <keyid|uid>进入密钥编辑模式,可以对已生成的主密钥进行编辑。下面将使用 addkey 命令生成一个仅用于签名的子密钥对。

$ gpg --edit-key E0772B35B2E02051
...

sec  rsa4096/E0772B35B2E02051
     创建于:2022-05-26  有效至:永不       可用于:SC
     信任度:绝对        有效性:绝对
ssb  rsa4096/E5B924315C3F59D1
     创建于:2022-05-26  有效至:永不       可用于:E
[ 绝对 ] (1). Sam Chu (Personal use only) <samchu-social@outlook.com>

gpg> addkey

# interactive instructions
...

sec  rsa4096/E0772B35B2E02051
     创建于:2022-05-26  有效至:永不       可用于:SC
     信任度:绝对        有效性:绝对
ssb  rsa4096/E5B924315C3F59D1
     创建于:2022-05-26  有效至:永不       可用于:E
ssb  rsa4096/823F7AE3713B71CB
     创建于:2022-05-26  有效至:永不       可用于:S
[ 绝对 ] (1). Sam Chu (Personal use only) <samchu-social@outlook.com>

gpg> save

生成过程与生成主密钥对类似,需要指定密钥类型、密钥长度、有效期限,随后会要求输入主密钥的密码,身份验证成功后便会收集用户动作以生成密钥。生成完毕后,可以看到新的仅用于签名的子密钥对已经添加到主密钥中了。最后输入 save 保存退出。

导出公钥

由于刚才生成的密钥对都是采用的非对称加密方式,所以我们需要分发自己的公钥来对消息进行加密或者签名。GPG 的子密钥的有效性都来自于主密钥的认证,所以导出的公钥实际为一组公钥,其中就有被主密钥认证之后的子公钥。使用以下命令可以将公钥以 ASCII 字符保存到 public.key 文件中。

$ gpg --export --armor --output public.key E0772B35B2E02051

当其他人获取该公钥后,可以使用以下命令导入自己的密钥环,方便进行加密信息交换。

$ gpg --import public.key
gpg: 密钥 E0772B35B2E02051:公钥 “Sam Chu (Personal use only) <samchu-social@outlook.com>” 已导入
gpg: 处理的总数:1
gpg: 已导入:1

备份私钥

同样的,如果需要备份私钥,可以将私钥导出后存放在绝对安全的地方进行备份。使用以下命令以备份整个私钥,执行时会要求输入主密钥的密码。

$ gpg --export-secret-keys --armor --output private.key E0772B35B2E02051

除了能够备份整个私钥,还能够单独将子密钥的私钥进行导出。导出时注意在 <subkeyid> 后加上 !,否则所有的子私钥都会被导出。

$ gpg --export-secret-subkeys --armor --output encrypt.subkey E5B924315C3F59D1! # export encrypt only subkey
$ gpg --export-secret-subkeys --armor --output sign.subkey F8A5FE5D5FA5BA9C!    # export sign only subkey

导入私钥时同样使用 gpg --import <file_of_private_key> 命令。

参考文章