GPG:您未充分利用的最佳免费加密工具,第二部分,共二部分
上个月,我介绍了 GNU Privacy Guard,这是一款免费但未被充分利用的 OpenPGP 加密标准实现。如您所知,GnuPG 在加密和解密电子文件(尤其是电子邮件)以及创建和验证数字签名方面非常有用。
但不幸的是,当我解释完公钥密码学和信任网络的基礎知识,更不用说尽我所能地吓唬您去互相签名密钥并检查未知密钥的有效性之后,在实际示例方面,剩下的空间只够放一些编译/安装建议以及关于验证数字签名文件的小教程。
好吧,本月是为更注重技术的读者准备的回报。让我们从上次结束的地方继续!
在您加密、解密或签名任何内容之前,您需要构建自己的公钥和私钥环;让我们从生成 GnuPG 密钥对开始。这是 gpg 更多交互式功能之一:命令语法非常简单,即 gpg --gen-key,它会在实际生成密钥之前触发一个问答环节。列表 1 显示了一个密钥生成会话的示例(用户输入以粗体显示)。如您所见,在生成密钥时,您需要决定几件事:密钥类型、密钥长度、过期日期以及您希望与密钥关联的电子邮件地址(身份)。
对于通用密钥对,请选择 DSA/ElGamal(选项 #1)。这实际上为您提供了两组密钥:一组 DSA 密钥对,gpg 将用于签名/验证;以及一组 ElGamal 密钥对,gpg 将用于加密/解密。不必担心这会使您需要管理的密钥数量翻倍:DSA 和 ElGamal 密钥存储为单个文件,两个公钥也是如此。
如果您想生成仅用于签名的密钥对,请选择仅 DSA(选项 #2)。如果您想要仅用于加密的密钥对,请选择仅 ElGamal(选项 #3)。
但是,我不建议创建双用途 ElGamal 密钥对(选项 #4)。在 《应用密码学》中,Bruce Schneier 描述了一种简单的攻击,它可以针对将同一密钥对用于签名和加密的方案。这种“选择明文”攻击是使用相同的密钥材料进行加密和数字签名的危险的教科书式例子。
密钥大小至关重要。GnuPG 支持的最小密钥大小为 768 位,但建议使用 1,024 位,因为它在安全性和性能之间取得了最佳平衡。(较长的密钥更安全,但计算和使用时间更长;较短的密钥计算和使用速度更快,但安全性较低。)请注意,当您选择组合的 DSA/ElGamal 密钥对时,DSA 密钥长度会自动设置为 1,024 位,而提示您输入的密钥长度实际上适用于 ElGamal 密钥。
接下来,您需要考虑您希望此密钥对在流通中保留多长时间。一方面,如果您的密钥永不过期,您就永远不必费力生成新的密钥对。 这样做的缺点是,如果您忘记了私钥的密码,并且没有创建和保存撤销证书(我稍后会解释),那么将密钥从它所列出的任何密钥服务器上删除将非常困难。
另一方面,如果您的密钥在一段时间后过期,那么您就永远不必担心过时的密钥无限期地滞留在公共密钥服务器上:如果您的电子邮件地址更改,您认为您的密钥长度不再足够,或者如果有人获得了您的私钥副本,您可以放心,即使由于某种原因您无法撤销旧密钥,它也会自然过期。有限寿命密钥的唯一缺点是需要定期生成、分发并让人们使用您的新密钥。
我过去只使用永不过期的密钥,但现在已经相信,过期日期的优点超过了缺点。因此,我建议您将密钥设置为在不超过 18 或 24 个月后过期。对我来说,一年太短了(时光飞逝!),但我怀疑一个比一年半或两年更老的密钥能够经受住计算能力和/或分解技术(即公钥破解方法)在其生命周期内不可避免的进步。
接下来,您需要指定姓名、电子邮件地址以及可选的注释。 请注意,您稍后可以使用 gpg 的 --edit-key 标志并发出 adduid 和/或 addkey 命令,将其他电子邮件地址与您的密钥关联起来。
您在生成密钥时需要考虑的最后一件事是一个好的密码。我指的是密码短语:它可以而且应该包含空格。它越长,就越安全。您还应该加入数字、混合大小写(例如,bOTTLE rockeT)和标点符号的某种组合。最近,我开始使用骰子和单词表来生成我的密码短语。请参阅 diceware.com 以获取有关自己执行此操作的便捷步骤。
无论您做什么,都不要选择简短、可预测或容易被猜到的密码短语。它不必看起来像“B1&SSja-sd0c as-d$%@KFSAAs-,ssd w0a-00sdp23m”,也不应该看起来像“My lame passphrase”。如果您这样做更容易使用难以猜测的密码短语,可以将您的密码短语写在一张小卡片上,放在钱包里。(只是要小心,永远不要随处乱放,并在用完后总是收好!)
生成密钥后,您应立即创建撤销证书。 这是一段文本字符串,如果您需要撤销密钥,可以将其发送到密钥服务器。
当然,您可以在任何时候创建撤销证书。 现在创建撤销证书的原因是,即使是非常博学和谨慎的人也常常忘记他们的密码短语。 您需要您的密码短语才能创建撤销证书,但不需要使用您之前创建的撤销证书。
这就是为什么现在创建一个撤销证书并将其保存在安全的地方是一个好主意(您甚至可以将其打印出来并保存在“肉身空间”中——撤销证书不是很长)。 只要确保将其文件权限设置为与您的私钥一样严格(例如,不可组或世界可读或可写)。 如果有人未经您的许可将证书发送到密钥服务器,其影响并不像有人真的可以使用您的私钥那么可怕,但至少过早撤销的密钥可能会给您带来不便。
要生成撤销证书,请输入此命令
gpg --output rev_cert_filename.asc --gen-revoke keyname
其中 rev_cert_filename.asc 是您希望证书拥有的文件名(只需确保它以 .asc 结尾),keyname 是密钥的 ID 号(例如,0586AF78)或您的部分身份(“Smooth JoJo”就足以识别我们的示例密钥)。
GnuPG 将其文件存储在您的主目录的子目录 .gnupg 中。 您拥有的任何私钥都存储在名为 secring.gpg 的文件中;公钥存储在 pubring.gpg 中。 默认情况下,secring.gpg 仅对您可读;保持这种状态。 保护此文件至关重要。 务必将其备份到软盘或 CD-ROM,但将备份保存在安全的地方。 如果任何人获得了您的秘密密钥环的副本,他们可能会猜测或暴力破解您的私钥密码,并有效地窃取您的身份(或至少能够解密您的东西)。
pubring.gpg 和 secring.gpg 都是二进制数据文件。 要在任一密钥环上添加、删除或更改密钥,您需要将各种标志与 gpg 命令一起使用。
例如,您会希望将您的公钥分发给您的朋友,对吧? 因此,让我们将该密钥从您的公钥环提取到一个文本文件中(请参阅边栏“装甲 ASCII 与二进制 GPG 文件”)。 要将您的公钥打印到屏幕上,以便在需要时复制和粘贴,您只需输入
gpg --armor --export
其输出结果将类似于列表 2。
我在这里稍微简化了一下;如果您不指定用户 ID,gpg 将转储您的默认密钥对的公共部分。 如果您只有一个私钥,那么该密钥对就是您的默认密钥,并且将转储该密钥对的公钥。
另一方面,如果您希望转储其他一些公钥,则需要指定用户 ID。 继续使用我们的 Figplucker 先生的示例,要显示 JoJo 的公钥,我们输入
gpg --armor --export jojo
如您所见,gpg 在尝试确定您要使用的密钥时相当智能。 实际上,它的工作方式很像 grep:如果您将您的电子邮件地址的片段或某些其他文本作为您的密钥标识符,gpg 将匹配用户 ID 包含该字符串的第一个密钥。 在管理我自己的密钥环时,其中我有多个私钥-公钥对,因此有许多包含我姓名的用户 ID,我发现最简单的方法是向 gpg 提供我希望在任何给定时间使用的密钥的完整电子邮件地址部分,例如,gpg --armor --export mick@visi.com。
顺便说一下,如果您想将密钥打印到文件而不是屏幕,请使用 --output 选项指定文件名。 要将 JoJo 的公钥写入文件 jojo_pub.asc,命令如下所示
gpg --armor --output jojo_pub.asc --export jojo
您是否备份了您的新密钥? 您可以考虑导出您的整个密钥对,包括您的私钥,但我建议不要这样做。 您最好只需将密钥环文件 pubring.gpg 和 secring.gpg 从 ~/.gnupg 复制到安全的地方。 但是,如果由于某种原因您确实需要导出您的整个密钥对,则它与导出公钥相同,只是您使用 --export-secret-keys 命令而不是 --export。
您的朋友 Dan Sparty 刚刚通过电子邮件向您发送了他的新公钥副本,文件名为 danskey.asc。 以下是如何将其导入到您的公钥环
gpg --import ./danskey.asc
但是,请稍等。 互联网电子邮件不是非常安全的媒介。 您如何知道 Dan 的密钥在传输过程中没有被篡改,或者甚至它是否是 Dan 发送的?
通过检查其指纹,就是这样。 每个 gpg 密钥都有一个安全哈希值,称为指纹,对于每个密钥(对)都是唯一的,但足够短,可以通过电话读取、写在明信片上等。 如果您打电话给 Dan,并要求他向您读取他的新密钥的指纹,它应该与以下命令的输出匹配(在您的系统上导入他的密钥后执行)
gpg --fingerprint dan
请注意,与 --export 命令一样,您可以仅指定密钥的一部分,只要该部分对于您希望指纹识别的密钥是唯一的。 输出将类似于以下内容
pub 1024D/C9F34866 2001-07-27 Dan Sparty (Party Down!) <dan@boogiemeister.org> Key fingerprint = D084 F92C EC62 8955 98E2 58FB 178A 2673 D1F3 6866 sub 1024g/C5569A5B 2001-07-27 [expires: 2001-08-10]或者(假设现在才中午,您不想吵醒 Dan),如果 Hugh 在他的电子邮件签名中包含此指纹,并且还在 Usenet 或公共电子邮件列表上发布了帖子,您可以简单地找到其中一条消息并比较该签名。 这说明了密钥指纹的一个重要方面:您的公钥和/或其指纹存档的位置越多,就越难让某人冒充您。
现在您知道这确实是 Dan 的新密钥,而不是伪造的,您可以公开地和以加密方式为它的真实性担保,从而帮助 Dan 和全世界。 换句话说,您可以使用您的私钥对其进行签名。 为此,您可以使用命令 --edit-key 运行 gpg。 与 --gen-key 一样,这将触发一个交互式会话。 列表 3 显示了一个密钥编辑会话,用户在其中使用他们自己的默认密钥对密钥进行签名。
您是否注意到最后的 save 命令? 这会保存您对密钥所做的任何更改(在本例中,是您为其创建的签名),并退出密钥编辑会话。 如果我们现在使用命令 gpg --list-sigs dan 列出密钥,我们将看到
jojo@linux:~ > gpg --list-sigs dan pub 1024D/B9E0868B 2001-07-27 Dan Sparty (Party On!) <dan@boogiemeister.org> sig B9E0868B 2001-07-27 Dan Sparty (Party On!) <dan@boogiemeister.org> sig C1C34866 2001-07-27 John J. Figplucker (Smooth JoJo) <jojo@figpluckers-supreme.to> sub 1024g/A0B78448 2001-07-27 [expires: 2001-08-26] sig B9E0868B 2001-07-27 Dan Sparty (Party On!) <dan@boogiemeister.org>
除了 Dan 自己的签名(当您生成密钥时,它会自动自签名),您现在可以看到 JoJo 的签名。 现在,剩下的就是让 JoJo 导出他的新签名版本的 Dan 的公钥
gpg --output dan_jojosig.asc --export dan然后 JoJo 需要通过电子邮件或其他方便的方式将此文件发送给 Dan(请记住,这是一个公钥,因此机密性不是问题),并且 Dan 需要将签名密钥导入回他自己的公钥环
gpg --import ./dan_jojosig.asc导入可能看起来违反直觉:Dan 实际上是在更新他的公钥,而不是导入新的公钥。 但请相信我,这就是他需要做的,才能加入那些真正费心让他们的朋友为他们的密钥担保的 gpg 用户的光荣行列。
现在 Dan 拥有了一个超级精英签名密钥,他已准备好将其发布到密钥服务器,以便其他人可以开始向他发送加密消息(并将他们的签名添加到他的密钥中)。 为此,他可以发出命令
gpg --keyserver pgp.mit.edu --send-keys dan@boogiemeister.org
选项 --keyserver 用于指定 PGP/GPG 密钥服务器的名称或 IP 地址。 或者,您可以将以下行添加到 ~/.gnupg/options
keyserver pgp.mit.edu但是,请注意,这样做会导致 gpg 在验证签名时遇到未知密钥时,自动从密钥服务器下载新密钥。
还记得上个月我验证软件包的独立签名文件吗? 第一次我尝试使用 gpgv 命令验证签名时,我收到了错误消息,因为用于创建签名的密钥不在我的公钥环中。
解决方案是从密钥服务器 pgp.mit.edu 查询并下载密钥;如果在我的 options 文件中设置了密钥服务器,这将自动发生。 这是否是一个功能或一个烦恼,以及因此是否使其成为默认行为,由您决定。(命令行选项 --no-auto-key-retrieve 将覆盖自动密钥检索。)
现在,终于,JoJo 准备好开始加密眼前的一切了。 假设 JoJo 想要向 Dan 发送一封加密的电子邮件。 他最常用的方法是使用他选择的文本编辑器或文字处理器撰写邮件,并将其保存到磁盘。 JoJo 使用 vi 写了一封信,并将其另存为 dan0729.txt。 然后,他使用以下命令对其进行加密
gpg --output dan0729.txt.asc --encrypt --recipient dan@boogiemeister.org dan0729.txt
最后,他将文件 dan0729.txt.asc 作为电子邮件附件发送,甚至列在电子邮件正文中(JoJo 的 options 文件中有一行“armor”)。
请注意,如果 JoJo 在加密时没有传递 gpg 的 --armor 标志,并且他的 options 文件中没有 armor 行,他应该将加密文件称为 dan0729.txt.gpg,因为它将以 gpg 二进制格式保存。 此外,它只能作为附件传输。 请记住,装甲 ASCII 更加通用。 如果文件大小很重要,则 gpg 二进制格式可能更可取,因为它往往比装甲 ASCII 产生更少的输出。
当 Dan 收到此文件时,他应将其保存到磁盘并使用以下命令解密
gpg --output dan0729.txt --decrypt dan0729.txt.asc
与加密不同,解密时您无需指定密钥。 gpg 会自动确定要尝试使用哪个密钥对其进行解密。 同样,Dan 尝试解密的文件是 gpg 二进制格式还是装甲 ASCII 格式都无关紧要; gpg 将在提示 Dan 输入密码短语后自动确定文件采用哪种格式。 如果 Dan 没有正确输入他的密码短语,gpg 将不会解密该文件。
签名和验证与解密和加密内容非常相似。 假设 JoJo 写了一封非机密但重要的信给 Dan,他希望 Dan 能够验证其有效性,但实际上不需要加密。 要对他的文件 beercontract.txt 进行签名,JoJo 将输入命令
gpg --output beercontract_signed.txt --clearsign beercontract.txt
这会将签名标头和页脚添加到文件中,并将其另存为 beercontract_signed.txt。 重要的是输出文件名与输入文件名不同,否则原始文件将被替换为空文件的签名。 当您希望能够将签名消息复制粘贴到电子邮件中或从电子邮件中复制粘贴出来,或者以其他方式将其视为纯文本时,应使用明文签名方法。
另一种方法是,您猜对了,创建二进制签名。 有两种类型。 要创建包含原始文档和签名的压缩二进制签名文件,请使用 --sign 命令而不是 --clearsign。 要创建包含签名但不包含其引用的文件的小得多的二进制文件,请使用 --detach-sig 命令。 --sign 和 --detach-sig 都应以 --output 指令开头。
当 Dan 收到 JoJo 的啤酒合同时,他可以通过将文件保存到磁盘(例如 bcs.asc)并输入命令来验证附加到它的签名
gpg --verify bcs.asc
请记住,如果 Dan 的密钥环中没有 JoJo 的公钥,gpg 将返回错误。 如果 Dan 确实有 JoJo 的公钥并且签名检查通过,gpg 将返回如下内容
gpg: Signature made Fri 27 Jul 2001 04:46:46 PM CDT using DSA key ID C1C34866 gpg: Good signature from "John J. Figplucker (Smooth JoJo) <jojo@figpluckers-supreme.to>"然后只有到那时,Dan 才能确定他刚刚收到的合同是由 JoJo 的私钥的持有者签名的。 JoJo 是否有可能被人用矛指着他的 屁股? 我们不知道。 JoJo 是否有可能将他的密码短语潦草地写在他的键盘底部,供他的办公室同事用于恶作剧? 同样,我们真的不知道。 但是,如果我们相信 JoJo 会正确使用和保护他的密钥,我们可以相当肯定他确实创建了这个有效的签名。
我希望您没有被所有这些选项、标志和命令搞得不知所措(欢迎来到 UNIX!)。 这实际上更像是一次调查,而不是其他;还有很多我没有介绍。 但我确实相信 gpg 是一款重要且有用的工具。 正因如此,许多人正在为它开发更友好的前端。 官方的 GnuPG GUI 称为 GNU Privacy Assistant (GPA),虽然它仍在开发中,但看起来确实很有前途。 它使用 GIMP 工具包,并且不出所料,看起来确实很漂亮。
处于不同开发阶段的其他 GUI 包括用于 GNOME 桌面的 Seahorse 和 GnomePGP;用于 KDE 的 Geheimnis;TkPGP(用 Tk 编写,因此相对而言与窗口管理器无关);以及各种包装器、插件和对流行的邮件用户代理(或 MUA,又名电子邮件客户端)的增强功能。 请参阅 GnuPG 主页的“前端”部分,以获取指向这些工具和其他工具的链接。
为期两个月的 GnuPG 基本用法教程到此结束。 这是一款我们中应该有更多人使用的工具,但目前使用的人数还不够。 因此,请大家去加密吧。 具体来说,使用由您认识的人签名和验证过的密钥进行加密。
顺便说一下,下个月我将离开去撰写一本关于 O'Reilly & Associates 的 Linux 安全方面的书。 但是,请不要害怕;在我离开期间,会找到一位能干的替代者来处理这个专栏,我将在下个月之后回来。 干杯!
