什么是 GPG

  • 1991 年,程序员Phil Zimmermann为了避开政府监视,开发了加密软件 PGP
  • PGP 是商业软件,不能自由使用,GNU 社区开发了 PGP 的替代品,取名 GnuPG,也即 GPG
  • GPG 的主要作用是文件加密和邮件加密

安装

1
2
3
4
# MacOS
brew install GPG
# Ubuntu
sudo apt-get install gnupg

生成 GPG 秘钥

1
gpg --gen-key

密钥管理

  • 列出密钥
1
2
3
4
5
6
7
$ gpg --list-secret-keys --keyid-format LONG
/Users/houmin/.gnupg/pubring.kbx
--------------------------------
sec   rsa2048/07CD597D75832B5B 2019-01-22 [SC] [expires: 2021-01-21]
      9B70573F6055FCF42C006CF107CD597D75832B5B
uid                 [ultimate] Houmin Wei <weihoumin@gmail.com>
ssb   rsa2048/0AF6FFF56550C6E1 2019-01-22 [E] [expires: 2021-01-21]
  • 删除密钥
1
$ gpg --delete-key [用户ID]
  • 输出密钥 公钥文件(.gnupg/pubring.gpg)以二进制形式储存,armor 参数可以将其转换为 ASCII 码显示。
1
$ gpg --armor --output public-key.txt --export [用户ID]

“用户 ID"指定哪个用户的公钥,output 参数指定输出文件名(public-key.txt)。

类似地,export-secret-keys 参数可以转换私钥。

1
$ gpg --armor --output private-key.txt --export-secret-keys
  • 上传公钥 公钥服务器是网络上专门储存用户公钥的服务器。send-keys 参数可以将公钥上传到服务器。
1
$ gpg --send-keys [用户ID] --keyserver hkp://subkeys.pgp.net

使用上面的命令,你的公钥就被传到了服务器 subkeys.pgp.net,然后通过交换机制,所有的公钥服务器最终都会包含你的公钥。

由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。通常,你可以在网站上公布一个公钥指纹,让其他人核对下载到的公钥是否为真。fingerprint 参数生成公钥指纹。

gpg –fingerprint [用户 ID]

  • 输入密钥 除了生成自己的密钥,还需要将他人的公钥或者你的其他密钥输入系统。这时可以使用 import 参数。

gpg –import [密钥文件]

为了获得他人的公钥,可以让对方直接发给你,或者到公钥服务器上寻找。

gpg –keyserver hkp://subkeys.pgp.net –search-keys [用户 ID]

正如前面提到的,我们无法保证服务器上的公钥是否可靠,下载后还需要用其他机制验证.

加密和解密

加密

假定有一个文本文件 demo.txt,怎样对它加密呢?

encrypt 参数用于加密。

gpg –recipient [用户 ID] –output demo.en.txt –encrypt demo.txt

recipient 参数指定接收者的公钥,output 参数指定加密后的文件名,encrypt 参数指定源文件。运行上面的命令后,demo.en.txt 就是已加密的文件,可以把它发给对方。

解密

对方收到加密文件以后,就用自己的私钥解密。

gpg –decrypt demo.en.txt –output demo.de.txt

decrypt 参数指定需要解密的文件,output 参数指定解密后生成的文件。运行上面的命令,demo.de.txt 就是解密后的文件。

GPG 允许省略 decrypt 参数。

gpg demo.en.txt

运行上面的命令以后,解密后的文件内容直接显示在标准输出。

签名

签名的原理是:用自己的私钥加密,对方用我的公钥解密。 只有用我的公钥才能够解密,其他的公钥不行。这就禁止了其他人仿照我的签名。

对文件签名

有时,我们不需要加密文件,只需要对文件签名,表示这个文件确实是我本人发出的。sign 参数用来签名。

gpg –sign demo.txt

运行上面的命令后,当前目录下生成 demo.txt.gpg 文件,这就是签名后的文件。这个文件默认采用二进制储存,如果想生成 ASCII 码的签名文件,可以使用 clearsign 参数。

gpg –clearsign demo.txt

运行上面的命令后 ,当前目录下生成 demo.txt.asc 文件,后缀名 asc 表示该文件是 ASCII 码形式的。

如果想生成单独的签名文件,与文件内容分开存放,可以使用 detach-sign 参数。

gpg –detach-sign demo.txt

运行上面的命令后,当前目录下生成一个单独的签名文件 demo.txt.sig。该文件是二进制形式的,如果想采用 ASCII 码形式,要加上 armor 参数。

gpg –armor –detach-sign demo.txt

签名+加密

上一节的参数,都是只签名不加密。如果想同时签名和加密,可以使用下面的命令。

gpg –local-user [发信者 ID] –recipient [接收者 ID] –armor –sign –encrypt demo.txt

local-user 参数指定用发信者的私钥签名,recipient 参数指定用接收者的公钥加密,armor 参数表示采用 ASCII 码形式显示,sign 参数表示需要签名,encrypt 参数表示指定源文件。

验证签名

我们收到别人签名后的文件,需要用对方的公钥验证签名是否为真。verify 参数用来验证。

gpg –verify demo.txt.asc demo.txt

Signed Commit Message

Why do I need it

Git 本身并没有检查是谁提交的 commit,提交者可以在提交的时候提供 author 和 email 信息

1
2
$ git commit --author="Linus Torvalds torvalds@linux-foundation.org" -m "Change grade"
这样,就可以在自己的repo 里伪造一个commit, 看起来是Linus Torvalds 提交的。

所谓的给 commit 消息签名,就是证明这个 commit 消息是你发布的。方法就是利用 GPG,用自己的私钥对 commit 消息加密,别人只有用你的公钥才能识别出来。

How to do it

[user]
    signingkey = ***
[alias]
    commit = commit -s
    amend = commit -s --amend
[commit]
    gpgsign = true
[gpg]
    program = gpg

对于已经 commit 的之前没有签名的 可以执行

$ git commit --amend -s
$ git push -f

Github GPG Signing Commit

  • 添加自己的公钥到 github
  • commit 的时候使用-s参数,也就是用你自己的私钥加密
  • 然后 github 就可以验证这是你 commit 的消息了,会在 commit 那里显示verified
  • 具体参考 https://help.github.com/articles/signing-commits/

Reference