在keyserver.ubuntu.com我查找了一个公钥,比如说这个,quux foo
用作搜索字符串,当你点击那里的任何超链接时,比如说第一个,你会得到这个,第一行和最后几行我将在下面显示:
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBFWnnlYBEACxP/X6kj+eOQepGtv5MGXKGvyfzrxWjf1MHP6CX+l932TtoC/a
mraSF4f4HI3i0p9BCbPCTxJSA5AkT0CgF34s3IqpR+vYF8wsdj3yvfvckN/2l72d
.
.
.
koiZ01CsJs1RzL1cNPx6MofudBq4tTwjtzx0hWYmkZqwGas8EQ+BDHHYOmDmflfK
6ovi3RGi9Js0vgSSDeFFVUO5YuIg0KHD
=mPX8
-----END PGP PUBLIC KEY BLOCK-----
我使用GnuPG,并执行以下操作:
$ gpg --keyserver keyserver.ubuntu.com --search-keys quux foo
结果如下:
gpg: data source: http://162.213.33.9:11371
(1) Anand Karthik (foo bar baz quux) <[email protected]>
4096 bit RSA key 1D94CC5AB7E8F5C6, created: 2015-07-16
Keys 1-1 of 1 for "quux foo". Enter number(s), N)ext, or Q)uit >
我在这里输入1
,显示如下:
gpg: key 1D94CC5AB7E8F5C6: public key "Anand Karthik (foo bar baz quux) <[email protected]>" imported
gpg: Total number processed: 1
gpg: imported: 1
执行gpg -k
显示密钥确实已成功导入:
.
.
pub rsa4096 2015-07-16 [SC]
B2219477E4935FF8929BEF311D94CC5AB7E8F5C6
uid [ unknown] Anand Karthik (foo bar baz quux) <[email protected]>
sub rsa4096 2015-07-16 [E]
现在我复制我认为是哈希 ( B2219477E4935FF8929BEF311D94CC5AB7E8F5C6
) 的内容,并尝试将密钥导出为文本文件:
$ gpg --export -a B2219477E4935FF8929BEF311D94CC5AB7E8F5C6
命令输出(中间缩短):
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFWnnlYBEACxP/X6kj+eOQepGtv5MGXKGvyfzrxWjf1MHP6CX+l932TtoC/a
mraSF4f4HI3i0p9BCbPCTxJSA5AkT0CgF34s3IqpR+vYF8wsdj3yvfvckN/2l72d
.
.
.
koiZ01CsJs1RzL1cNPx6MofudBq4tTwjtzx0hWYmkZqwGas8EQ+BDHHYOmDmflfK
6ovi3RGi9Js0vgSSDeFFVUO5YuIg0KHD
=Pj2c
-----END PGP PUBLIC KEY BLOCK-----
这看起来不像网站上的密钥。我究竟做错了什么?
它实际上看起来很像网站上的密钥——只是开头和中间的几个字符不同1。事实上,如果你去掉 Base64 编码
gpg --dearmor
,然后对结果文件进行二进制比较,你只会看到这些差异:有一个模式。OpenPGP 消息是基于数据包的,通过提供密钥
gpg --list-packets
或pgpdump
将揭示“密钥”由链接在一起的几个组件组成:“主”密钥对的公钥数据包,后跟用户 ID(每个后跟签名),然后后跟子键(每个子键后跟签名)。这把钥匙相当标准,有五个数据包.........并且有五个看起来相似的差异,这强烈表明它们对应于数据包标头。此外,仔细观察
gpg --list-packet
输出,它实际上恰好显示了数据包标头的差异:OpenPGP 使用的二进制编码不像 X.509 中使用的 DER 那样严格,所以可以有不止一种方法来做同样的事情。查看RFC 4880(OpenPGP 规范),第一个字节(gpg 表示为“ctb=”)是一个标记字节,表示数据包格式,它本身有两个版本——这导致了主要区别:
“新”格式允许实际类型为 6 位(允许 64 种不同的数据包类型),而“旧”格式仅保留 4 位(限制为 16 种数据包类型)。查看源代码,似乎 GnuPG 会生成旧格式的标签,只要它可以摆脱它,只会切换到类型 ≥16 的新格式,从而最大限度地兼容早于 RFC 4880 的旧 PGP 实现。
这两个标签版本还对“数据包长度”字段进行了不同的编码,这就是导致每个标头的字节 2-3 存在差异的原因。
1请注意,PGP 装甲消息的最后一行(以 开头
=
)是用于检测损坏(24 位 CRC)的校验和,因此即使只有一个字节发生变化,它自然也会有很大不同。这个校验和是 ASCII-armor 格式的一部分——它不是编码数据的一部分,也不会出现在二进制差异中。