GPG 入门

GnuPG

PGP 是一个基于 RSAAES 的加密软件实现. 后来被赛门铁克所收购.

GnuPG 是一个 PGP 的开源免费实现.
GPG 可以用来实现非对称的文件加密, 对数据进行签名等操作.
在 2.0 版本的 GPG 还实现了从 GPG 导出可用于 SSH 登陆的公钥. 再借助 gpg 代理来实现ssh登陆.

使用

要使用 GPG, 首先需要生成一对自己的密钥对. 或者如果只想用来验证别人的签名的话, 也可以导入其他人的公钥.

生成密钥对

生成密钥对可以直接使用

gpg --generate-key

来快速生成一个密钥对, 或者使用

gpg --full-generate-key

来启用更详细的生成功能, 能生成更加自定义的密钥对,

生成时可选密钥长度, 默认是 2048, 不过更推荐使用 4096, 安全性会更高.

在生成的时候只需要输入自己的名字和邮箱就可以直接生成.
备注是可有可无的.

主钥和子钥

GPG 设定中, 有主钥和子钥的概念, 主钥和子钥都可以指定不同的用途. 当使用默认参数生成一对密钥的时候, 首先会生成一个主密钥, 这个主密钥默认拥有 签名[S]和认证[C] 的用途.
同时还会生成一个子密钥, 这个子密钥默认用途只有加密[E]. 当主密钥对子密钥认证[C]之后这个子密钥就和主密钥”绑定”在了一起.

因此日常的加密和签名操作是更推荐使用子密钥来进行, 而主密钥一般情况下是不使用的.

摘录一部分 debian 社区的说法:

when you sign someone else’s key or revoke an existing signature,
when you add a new UID or mark an existing UID as primary,
when you create a new subkey,
when you revoke an existing UID or subkey,
when you change the preferences (e.g., with setpref) on a UID,
when you change the expiration date on your master key or any of its subkey, or
when you revoke or generate a revocation certificate for the complete key.

管理密钥

一般来说生成和导入的密钥都存放在 ~/.gnupg/pubring.kbx 这个文件里.
可以使用 gpg -k 来列出所有的key, 包括自己生成的和导入的.
效果可能类似于:

-----------------------------
pub   rsa4096/8D56CBEF 2017-07-17 [C]
      96BD73741D182C51FE161DDC716053928D56CBEF
uid         [ 绝对 ] Snow Star (Snow Star) <[email protected]>
sub   rsa4096/325707A7 2017-07-17 [E]
sub   rsa4096/EECEF2FD 2017-07-17 [S]
sub   rsa4096/14E2D3C9 2017-07-17 [A] [有效至:2018-07-17]

pub   rsa4096/6092693E 2011-09-23 [SC]
      647F28654894E3BD457199BE38DBBDC86092693E
uid         [ 完全 ] Greg Kroah-Hartman (Linux kernel stable release signing key) <[email protected]>
sub   rsa4096/76D54749 2011-09-23 [E]

pub   rsa2048/00411886 2011-09-20 [SC]
      ABAF11C65A2970B130ABE3C479BE3E4300411886
uid         [ 完全 ] Linus Torvalds <[email protected]>
sub   rsa2048/012F54CA 2011-09-20 [E]

可以看到第一个是我自己的密钥对. 第二个第三个是导入的 Linus 和 Greg 的公钥.
通常每一组会包含三部分内容.

pub 是公钥特征, 包括长度和他的 ID, 以及创建日期, 有些情况下还会显示他的用途.
uid 是用户id, 包括用户名, 邮箱等信息.
sub 是子密钥的特征, 格式和 pub 类似, 不同之处在于 sub 可以出现很多次, 表明有多个子密钥.

如果只想列出拥有私钥的密钥对, 可以使用 gpg -K, 输出大概类似于

-----------------------------
sec   rsa4096/8D56CBEF 2017-07-17 [C]
      96BD73741D182C51FE161DDC716053928D56CBEF
uid         [ 绝对 ] Snow Star (Snow Star) <[email protected]>
ssb>  rsa4096/325707A7 2017-07-17 [E]
ssb>  rsa4096/EECEF2FD 2017-07-17 [S]
ssb>  rsa4096/14E2D3C9 2017-07-17 [A] [有效至:2018-07-17]

输出和之前的差不多, 不同之处在于 pub 变成了 sec, 代表这是私钥, sub 变成了 ssb, 代表这是子密钥的私钥.

导出

对于密钥的导出, gpg 提供了三个选项:
* --export 仅导出公钥
* --export-secret-keys 导出私钥. 私钥内包含了公钥.
* --export-secret-subkeys 只导出子密钥的私钥.

在导出时默认使用的是二进制的储存, 如果想导出成ASCII显示的, 可以加上参数 --armor

导入

导入其实很简单, 只需要简单的使用 --import 就可以导入.

用途?

加密与解密

非对称加密的一个特点就是, 使用公钥加密, 使用私钥来解密. 因此在加密的时候需要指定一个公钥用来加密, 通常这个公钥是对方的公钥.
例如我想给 linus 发送一个加密文件, 只需要:

gpg -r linus -e xxx.txt

这样就会生成一个 xxx.txt.gpg 的加密文件, 通过 file 可以看到类型是 RSA 加密文件:

> file xxx.txt.gpg
xxx.txt.gpg: PGP RSA encrypted session key - keyid: FE8BC88 CA542F01 RSA (Encrypt or Sign) 2048b .

当你尝试解密的时候就会报错:

> gpg -d xxx.txt.gpg
gpg: 由 2048 位的 RSA 密钥加密,钥匙号为 012F54CA、生成于 2011-09-20
      “Linus Torvalds <[email protected]>”
gpg: 解密失败:没有秘匙

因为你并没有 linus 的私钥, 所以这个文件你自己是解密不了的.

如果你希望这个文件你自己也可以解密, 是可以把自己也加入到接受者列表的:

gpg -r linus -r snowstar -e xxx.txt

多次使用 -r 参数来指定多个接受者, 任何一个在接受者列表的人都可以使用自己对应的私钥来解密文件.

解密的时候注意要加 --output 参数指定输出文件, 不然你的终端就会被二进制数据塞满

签名

gpg 的另一个重要用处就是签名, 签名可以证明文件从签名之后是没有被修改过的, 或者证明这个文件是你发出的, 而不是别人冒充你.

签名一共有三种储存形式:
* 二进制压缩储存 (默认)
* ASCII 格式储存
* ASCII 分离式储存

gpg -s xxx.txt

默认情况下 gpg 会生成二进制的签名文件 xxx.txt.gpg 这个文件同时默认也是压缩储存的.

如果想生成第二种 ASCII 格式的话, 同样改成 --clearsign 参数, 这将会生成一个 xxx.txt.asc 的文件, 其中签名是以 base64 编码之后的形式跟在文件末尾的.

当然也可以生成第三种签名:

gpg --detach-sign xxx.txt

这会生成一个 xxx.txt.sig 的独立签名文件, 内容不会包括被签名的文件内容, 而前两种都包括了源文件.

拥有签名时候用的公钥可以进行验证:

> gpg --verify xxx.txt.gpg
gpg: 签名建立于 2018年05月26日 星期六 11时37分56秒 CST
gpg:               使用 RSA 密钥 25A665D2AC3CFA0DB54030BC90FB43EBEECEF2FD
gpg: 完好的签名,来自于“Snow Star (Snow Star) <[email protected]>” [绝对]

如果想顺便把文件也提取出来:

gpg --output xxx.txt -d xxx.txt.gpg

GPG 签名和 Git

git 在 1.7.9 引入了对提交记录的签名功能, 可以使用 gpg 来对你的提交进行签名, 只需要告诉 git 你需要用哪个密钥来签名就可以. 而在 1.7.9 之前似乎只能对 tag 进行签名.

git config --global user.signingkey [ID]

在之后的提交时, 只需要加入 -S 参数就可以对提交进行签名. 例如

git commit -S

有什么用?

Git 虽然是密码级安全的,但它不是万无一失的。

即使 Git 通常有密码或者密钥来保护, 但提交记录的用户名和邮箱却是随便设置的, 这难免会出现一些问题, 如果有人对代码做了破坏工作, 并且把提交时候的用户名和邮箱改成你的. 你可就跳进黄河也洗不清了. 但如果服务器开启来拒绝接受未签名的提交记录, 即使提交记录显示用户名和邮箱是你的, 但签名不是你的, 在某种程度上可以证明你的清白.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注