GnuPG
PGP
是一个基于 RSA
和 AES
的加密软件实现. 后来被赛门铁克所收购.
而 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 通常有密码或者密钥来保护, 但提交记录的用户名和邮箱却是随便设置的, 这难免会出现一些问题, 如果有人对代码做了破坏工作, 并且把提交时候的用户名和邮箱改成你的. 你可就跳进黄河也洗不清了. 但如果服务器开启来拒绝接受未签名的提交记录, 即使提交记录显示用户名和邮箱是你的, 但签名不是你的, 在某种程度上可以证明你的清白.