GPG 的正确使用姿势

一篇“最硬核”的 GPG 使用指南

15 min read

{{< featuredImage >}}

这篇指南面向的是对 GPG 有一定基础的同学,如果你连 GPG 是什么都不知道的话可能需要先了解一些基础知识

前面的一篇文章提到了如果使用 GPG 创建密钥,以及如果使用 GPG 签名 Git Commit 和 Git Tag,但其中提到的使用方法实际上并不标准。

后来经过大量的学习与思考,总结出了这篇“最硬核”的 GPG 使用指南,你当然不需要完全照着文章中操作,但核心思想还是可以参考一下的。

虽说是“最硬核”的 GPG 使用指南,但我仍然会尽我所能用最通俗的语言让每个人都能看懂。

首先需要准备两个 U 盘,为了方便区分,就分别标注他们为 0号U盘1号U盘。U 盘大小没有要求,50 M 都绰绰有余了 {{< spoiler >}}现在应该买不到这样的 U 盘了吧 |・ω・`){{< /spoiler >}}但是必须保证 U 盘安全无毒

核心思想

其实本文的核心思想总结起来就一句话:我们应该使用且只使用子密钥,主密钥应该放在一个绝对安全的地方。

创建密钥对

让我们来创建一个新的 GPG 密钥对,强烈建议在无网的 Linux 虚拟机环境中操作

「使用 GPG 签名你的 Git Commit」这篇文章中,我们使用的是 --gen-key 来生成 GPG 密钥对,这样可以快速的生成一个可用的密钥对,但有的细节性的设置却不好设置

这里我们使用 --full-gen-key 来生成密钥对,首先选择密钥类型,选择 1 (默认) 即可

$ gpg --full-gen-key
gpg (GnuPG) 2.2.15; Copyright (C) 2019 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.

请选择您要使用的密钥类型:
   (1) RSA RSA (默认)
   (2) DSA Elgamal
   (3) DSA(仅用于签名)
   (4) RSA(仅用于签名)
您的选择是? 1

然后选择密钥长度,没有特殊需求的话保持 2048 的默认选项即可

RSA 密钥的长度应在 1024 位与 4096 位之间。
您想要使用的密钥长度?(2048) 2048

然后设置密钥的有效期,因为我们需要长期使用,所以选择 0 ,密钥永不过期

请设定这个密钥的有效期限。
         0 = 密钥永不过期
      <n>  = 密钥在 n 天后过期
      <n>w = 密钥在 n 周后过期
      <n>m = 密钥在 n 月后过期
      <n>y = 密钥在 n 年后过期
密钥的有效期限是?(0) 0

确定后,依次输入姓名、电子邮件和注释 (可以不填),然后选择 o 确定

GnuPG 需要构建用户标识以辨认您的密钥。

真实姓名: Mogeko
电子邮件地址: zhengjunyi@live.com
注释:
您选定了此用户标识:
    “Mogeko <zhengjunyi@live.com>

更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? o

然后输入并确认你密钥的密码

Set Password

Set Password

在这个步骤中可以做些其他操作,因为

我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数发生器有更好的机会获得足够的熵

如果看到一下输出就说明生成成功了

gpg: 密钥 71C861745213C7DC 被标记为绝对信任
gpg: 吊销证书已被存储为‘/home/mogeko/.gnupg/openpgp-revocs.d/7E99AAF646B8B572979266C471C861745213C7DC.rev’
公钥和私钥已经生成并被签名。

pub   rsa2048 2019-05-30 [SC]
      7E99AAF646B8B572979266C471C861745213C7DC
uid                      Mogeko <zhengnyi@live.com>
sub   rsa2048 2019-05-30 [E]

创建子密钥

我们刚刚生成的密钥名为 71C861745213C7DC,这个同时也是我们的公钥。无论加密还是签名都可以直接使用这个公钥,但我们并不推荐这样做,因为如果直接使用这个公钥,而密钥又不小心被泄露了,我们就不得不吊销整个密钥。

为了解决这一问题,我们应该使用且只使用子密钥,这样如果子密钥被泄露了,我们仅需要吊销被泄露的子密钥,这样主密钥仍是安全的,然后用主密钥生成新的子密钥继续使用。

生成主密钥对的时候 GPG 已经为我们生成了一对有效期与主密钥相同,ElGamal (仅用于加密) 的子密钥对,但我们最好还是生成和使用一对新的子密钥。

想要生成子密钥,我们需要使用 GPG 选项 --edit-key + 密钥名称编辑密钥,然后输入 GPG 命令 addkey

$ gpg --edit-key 71C861745213C7DC
gpg (GnuPG) 2.2.15; Copyright (C) 2019 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.

私钥可用。

sec  rsa2048/71C861745213C7DC
     创建于:2019-05-30  有效至:永不       可用于:SC
     信任度:绝对        有效性:绝对
ssb  rsa2048/57440229D371DCD4
     创建于:2019-05-30  有效至:永不       可用于:E
[ 绝对 ] (1). Mogeko <test@live.com>

gpg> addkey

然后选择子密钥的密钥类型,根据实际需求选择即可

请选择您要使用的密钥类型:
   (3) DSA(仅用于签名)
   (4) RSA(仅用于签名)
   (5) ElGamal(仅用于加密)
   (6) RSA(仅用于加密)
您的选择是? 4

选择密钥长度,同样的默认 2048 即可

RSA 密钥的长度应在 1024 位与 4096 位之间。
您想要使用的密钥长度?(2048) 2048

然后选择密钥有效期,这里不推荐默认选项 0 (永不过期),推荐使用选项 1y (一年有效期)

请设定这个密钥的有效期限。
         0 = 密钥永不过期
      <n>  = 密钥在 n 天后过期
      <n>w = 密钥在 n 周后过期
      <n>m = 密钥在 n 月后过期
      <n>y = 密钥在 n 年后过期
密钥的有效期限是?(0) 1y

输入密钥的密码

Verifcation

然后确认一下密钥信息,然后输入 save 保存密钥

sec  rsa2048/71C861745213C7DC
     创建于:2019-05-30  有效至:永不       可用于:SC
     信任度:绝对        有效性:绝对
ssb  rsa2048/57440229D371DCD4
     创建于:2019-05-30  有效至:永不       可用于:E
ssb  rsa2048/8873AB36406A34F5
     创建于:2019-05-30  有效至:2020-05-29  可用于:S
[ 绝对 ] (1). Mogeko <zhengjunyi@live.com>

gpg> save

然后 8873AB36406A34F5 就是我们的子密钥名称,同时也是子公钥,平常使用的公钥也是这个

导出密钥、子密钥和吊销证书

现在,我们准备的两个 U 盘终于可以派上用场了。

将 U 盘格式化 (文件系统最好选择 fat32,以保证最好的兼容性),然后将 U 盘挂载到虚拟机上 (如果使用了虚拟机的话),我这里将 0号U盘挂载到了 /run/media/mogeko/USB0/,将 1号U盘挂载到了 /run/media/mogeko/USB1/

然后导出 GPG 的密钥、子密钥和吊销证书。

使用以下命令导出密钥到 0号U盘,然后输入密码

gpg -o /run/media/mogeko/USB0/gpg_key --export-secret-keys 71C861745213C7DC

使用以下命令导出子密钥到 1号U盘,同样需要输入密码

gpg -o /run/media/mogeko/USB1/gpg_key.sub --export-secret-subkeys 71C861745213C7DC

然后导出吊销证书,可以使用以下命令生成

gpg --generate-revocation 71C861745213C7DC

不过实际上在生成密匙时就已经生成了一份吊销证书了,放在这个目录下面 ~/.gnupg/openpgp-revocs.d/,我们也可以直接将它移动到 0号U盘

mv ~/.gnupg/openpgp-revocs.d/2B452412DF8969D5682E279A71C861745213C7DC.rev /run/media/mogeko/USB0/revoke.rev

总结一下,现在 0号U盘里有 gpg_keyrevoke.rev,现在 1号U盘里有 gpg_key.sub

分别卸载两个U盘,然后将 0号U盘保存到一个绝对安全的地方,例如银行的个人保险柜。

卸载密钥

现在使用以下命令卸载刚刚生成的密钥

gpg --delete-secret-keys 71C861745213C7DC

然后清理吊销证书,将当前环境恢复到生成密钥前的样子。

如果是虚拟机的话就跟方便了,直接删除整个虚拟机。

为什么要卸载密钥呢?为了防止主密钥在使用过程中不小心被泄露,就像我刚刚说的:我们应该使用且只使用子密钥,主密钥应该放在一个绝对安全的地方。

导入子密钥

在断网的环境下,将 1号U盘插入到需要使用 GPG 的电脑上。

使用以下命令将子密钥导入到本地,并输入密码

$ gpg --import /run/media/mogeko/USB1/gpg_key.sub
gpg: 密钥 71C861745213C7DC:公钥 “Mogeko <zhengjunyi@live.com> 已导入
gpg: 要迁移 ‘secring.gpg’,对每一张智能卡,执行:gpg --card-status
gpg: 密钥 71C861745213C7DC:私钥已导入
gpg: 处理的总数:1
gpg:    未改变:1
gpg: 读取的私钥:1
gpg: 导入的私钥:1

使用以下命令查看密钥

$ gpg -K
/home/mogeko/.gnupg/pubring.kbx
-------------------------------
sec#  rsa2048 2019-05-30 [SC]
      7E99AAF646B8B572979266C471C861745213C7DC
uid           [ 未知 ] Mogeko <zhengjunyi@live.com>
ssb   rsa2048 2019-05-30 [E]
ssb   rsa2048 2019-05-30 [S] [有效至:2020-05-29]

sec 后面带 #,表示我们安装的是子密钥,并且密钥不在本地。

这样就可以安心的使用了!

修改密钥的信任度

因为我们的密钥是从 U 盘导入进来的,所以 GPG 对于这个密钥的信任度是未知。

我们可以使用 GPG 选项 --edit-key + 密钥名称编辑密钥,修改 GPG 对密钥的信任度

$ gpg --edit-key 71C861745213C7DC
gpg (GnuPG) 2.2.15; Copyright (C) 2019 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  rsa2048/71C861745213C7DC
     创建于:2019-05-30  有效至:永不       可用于:SC
     信任度:未知        有效性:未知
ssb  rsa2048/57440229D371DCD4
     创建于:2019-05-30  有效至:永不       可用于:E
ssb  rsa2048/8873AB36406A34F5
     创建于:2019-05-30  有效至:2020-05-29  可用于:S
[ 未知 ] (1). Mogeko <zhengjunyi@live.com>

gpg> trust

输入 GPG 命令 trust,然后根据实际情况修改 GPG 对于密钥的信任度

pub  rsa2048/71C861745213C7DC
     创建于:2019-05-30  有效至:永不       可用于:SC
     信任度:未知        有效性:未知
ssb  rsa2048/57440229D371DCD4
     创建于:2019-05-30  有效至:永不       可用于:E
ssb  rsa2048/8873AB36406A34F5
     创建于:2019-05-30  有效至:2020-05-29  可用于:S
[ 未知 ] (1). Mogeko <zhengjunyi@live.com>

请决定您对这名用户能否正确地验证其他用户密钥
(通过查看护照,检查不同来源的的指纹等等)的相信程度

  1 = 我不知道或不作答
  2 = 我不相信
  3 = 我勉强相信
  4 = 我完全相信
  5 = 我绝对相信
  m = 回到主菜单

您的决定是什么? 5

信任度修改之后,在重启程序之前,所显示的密钥有效性不一定正确

因为我们只是修改了 GPG 对密钥的信任度,并没有修改密钥的元数据,所以直接使用 quit 退出

pub  rsa2048/71C861745213C7DC
     创建于:2019-05-30  有效至:永不       可用于:SC
     信任度:绝对        有效性:未知
ssb  rsa2048/57440229D371DCD4
     创建于:2019-05-30  有效至:永不       可用于:E
ssb  rsa2048/8873AB36406A34F5
     创建于:2019-05-30  有效至:2020-05-29  可用于:S
[ 未知 ] (1). Mogeko <zhengjunyi@live.com>
请注意,在您重启程序之前,所显示的密钥有效性不一定正确。

gpg> quit

发送公钥到公钥服务器

将公钥发送到公钥服务器上,方便别人取用

$ gpg --send-keys 71C861745213C7DC
gpg: 正在发送密钥 71C861745213C7DC hkps://hkps.pool.sks-keyservers.net