EMACS-DOCUMENT

=============>集思广益

在Emacs中借助GnuPG与Auth-Source保管你的秘密

用明文存储机密信息可不好. 如果你非常在意你的机密(若你已经被监控起来了,那么你怎么在意都不过分),那么这篇文章中的建议恐怕还远远不能满足你的需求; 但是对于大多数人来说,用加密的文件来保存机密信息已经足够安全了.

自然,Emacs有多种方式为你加密.

Emacs原生支持GnuPG加密.借助一个名为EasyPG的package(或者缩写为epa)可以对文件进行加签/验证,加密/解密等操作. 我还会告诉你如何使用auth-source这个package(它为不同的加密后端提供了一个统一的接口)来自动登录到各种外部服务上去(需要设置公私密钥).

1 Keeping Secrets in Emacs with GnuPG & EasyPG

GNU Privacy Guard (GnuPG)是OpenPGP标准的一个实现. 它十分的强大,同时支持对称加密与非对称加密. 你可以用它对对二进制文件或归档文件进行签名,用非对称密钥对文件进行加解密,也可以用对称加密的方法对文件进行加密. GPG,你值得拥有.

而且GnuPG也与Emacs整合的很好,Emacs内建了一个名为EasyPG的package,可以提供基本的GnuPG功能.

你即能用EasyPG来对文件加签,也能用它来验签,即能用对文件加密也能用来解密,而且同时支持对称和非对称加解密.

2 GPG v1 versus GPG v2

若你使用EasyPG时发生错误,告诉你找不到gpg程序,那通常是因为你安装的是第二版的GPG,它的文件名是gpg2. 你可以设置一下 epg-gpg-program 的值:

(setq epg-gpg-program "gpg2")

3 Transparent File Cryptography with EasyPG

EasyPG最好用的一个功能是它会在你打开文件时自动解密,然后在保存是自动加密,整个过程对你来说是透明的.

EasyPG package会添加几个hook到Emacs,它会自动地探测一个文件是否为GnuPG加密过的文件. 变量 auto-mode-alist 决定了Emacs打开某个文件时会进入哪个major mode. 在我这,以 .gpg 结尾的文件被认为是经过GnuPG加密过的文件.

你可以测试一下,打开一个文件(例如 /tmp/foobar.gpg),写入一些内容,在按下 C-x C-s 保存它. 会发现Emacs提示你选择一个密钥来加密,如果你没有选择任何密钥,则会提示你输入用于对称加密的密码.

然后你再重新打开这个文件,会发现Emacs提示你输入上次加密时的密码,然后Emacs会对文件进行解密并打开它.

不仅如此,它还支持嵌套的文件扩展名: 例如打开一个名为 .py.gpg 的文件,Emacs会先对它进行解密然后用普通的python-mode打开它. 对加密过的压缩归档文件也是一样,打开后缀为 .tar.gz.gpg 的文件,Emacs会先解密然后用auto-compression-mode打开它.

4 Interactive Commands

EasyPG有一些方便的快捷键:

Command Description M-x epa-list-keys 列出所有私钥/公钥 M-x epa-list-secret-keysList M-x epa-verify-<region|file> 校验当前region/文件 M-x epa-sign-<region|file> 对当前region/文件加签 M-x epa-insert-keys 在buffer中插入一个或多个密钥 M-x epa-decrypt-<region|file> 解密当前region/文件 M-x epa-encrypt-<region|file> 加密当前region/文件

大多数的命令命名方式都遵照一定模式,并且他们的功能也很直观. M-x epa-list-keysM-x epa-list-secret-keys 都会列出你系统中密钥链中的密钥. 你也可以用Emacs Secrets package (下面会说到)或系统自带的工具(例如Ubuntu的seahorse)来查看这些密钥.

5 Dired

借助Emacs巧妙的auto-mode-alist体系,你可以在Dired中直接打开.gpg文件,跟你在其他地方打开.gpg文件没什么两样. 不过Dired还为EasyPG提供了一些好用的快捷键:

Key Binding Description
: d Decrypt marked or selected
: e Encrypt marked or selected
: s Sign marked or selected
: v Signs the current buffer

如果你mark了多个文件,则Dired会应用命令到这些文件上,否则会应用命令到光标所在的文件上.

要注意:如果你想将多个文件加密成一个.gpg文件,你需要先把这些文件压缩成一个文件: mark好要被压缩的文件,再按下 c,然后输入要压缩成的目标文件名. Emacs就会根据目标文件的文件扩展名(.tar.gz, .zip等等)自动选择合适的压缩命令去压缩这些文件,然后你就可以对产生的压缩文件进行加密了.

6 Disabling External Pin Entry

你可以强制让GPG不要用外部工具来读取PIN码. 这在你不希望启用默认的GPG Agent pin entry工具,而希望Emacs来为你管理pin entry时尤其有用.

有很多中方法都能做到这一步(具体的方法跟你的操作系统发行版与窗口管理器有关),不过最简单的在Emacs中禁用agent info的方法是执行下面代码:

(setenv "GPG_AGENT_INFO" nil)

这会强制让Emacs用它自己的内部密码提示功能而不会调用外部的pin entry程序来读取PIN码.

7 Using Keys to Store Secrets

NOTE: 请注意,这只是一篇关于Emacs的博文,而不是专业讲安全的文章. 我们只会列出一些如何在Emacs中使用GPG功能的指导意见.

我之前提到过的,通过对称密码可以透明地加解密文件,操作起来很简单. 但是跟使用非对称加密的方式比较起来还是显得麻烦了一些. 使用非对称密钥加密的好处在于你可以将密钥保存在内存中让Emacs自动加解密文件而无需再次提示你输入密码了.

8 Creating a key

第一步,你需要使用gpg产生一个密钥对:

gpg --gen-key

照者提示一步步下去就能产生密钥了. 我强烈推荐你输入一个密码来保护你的密钥!

你可以通过在Emacs中运行 M-x epa-list-secret-keys 来检查密钥是否加载了.

你也可以在命令行中运行 gpg --list-secret-keys 来检查密钥是否加载了, 这时你可能会得到类似下面的结果:

$ gpg --list-secret-keys

sec   2048R/5DB69AC1 2016-06-13
uid                  Cosmo Kramer (Kramerica Industries) <kramer@example.com>
ssb   2048R/02A89A28 2016-06-13

当然你也可以使用类似seahorse这类带界面的程序来检查.

9 Exporting and Re-Importing a Key

第二步,将密钥导出到文件中,需要指定密钥持有人的名称,email地址或密钥的ID:

gpg --armor --export-secret-keys Cosmo Kramer > mykey.asc

现在你可以在别的机器上重新导入这个key了, but you will also have to trust it again. 你可以传递你的全称(放在引号内)或email地址給gpg,它会帮你选择正确的那个key. 下面的例子中我在修改该key传递了密钥持有人的全称进去,gpg会自动帮你找出要修改的是哪个密钥:

$ gpg --import mykey.asc
$ gpg --edit-key "Cosmo Kramer"
gpg> trust
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
gpg> quit

现在你已经知道怎么创建一个密钥,也知道如何在不同电脑之间导出/导入密钥了. 但是要注意,若你丢失密钥,则你也就丢失了这些加过密的数据了!

10 Encrypting Data with a Key

你可以告诉EasyPG自动用哪个密钥来加解密. 只需要设置一下文件局部变量 epa-file-encrypt-to that 就行了.

下面是一个简单的例子. 创建一个名为you-secrets.el的elips文件,输入下面内容:

# -*- epa-file-encrypt-to: ("kramer@example.com") -*-

(setq jabber-account-list ...)
(setq my-secret-password "rosebud")

这里 kramer@example.com 就是我们上面例子中船舰的密钥的email. 这里之所有使用email而不是key ID是因为email更易读一些.

然后执行 M-x epa-encrypt-file 来加密这个文件,并选择上面那个密钥来加密. 下一次你再保存这个文件时,Emacs会自动选择正确的那个密钥并对它进行加密处理.

现在你可以在你的 init.el 中加载这个文件了:

(load-library "/path/to/your-secrets.el.gpg")

Emacs会提示你输入该密钥的保护密码,然后像普通文件那样加载这个elisp文件.

11 Storing Credentials with the Auth Source Package

这部分内容是基于 Using Keys to Store Secrets 之上的.

Auth Source 为各种常见的后端(例如操作系统的Keychain,本地的~/.authinfo和~/.netrc文件)提供了一个统一的接口.

很多Emacs package 都用到了 Auth Source, 因为它提供了一个很简单易用的API. 这些Package包括 jabber.el, GNUS, TRAMP, 各种内置的网络相关的函数, LDAP (使得Emacs内置了一个LDAP客户端), 以及 ERC.

Auth Source 解决了保存某台主机上用户名与密码的问题,并且它还支持多种后端,允许你将证书存放在多个地方.

12 Debugging Authentication Issues

首先我要提一下有关调试的变量. 在没有添加一个中间层的条件下调试认证问题是很困难的一件事情. 要开启调试信息,需要设置变量 auth-source-debug, t 表示启用调试信息, nil 表示禁用调试信息:

(setq auth-source-debug t)

这样就会在 *Messages* buffer中显示很多附加的有用的信息. 请一定记得在调试完后把这个值再设置成nil.

调试时另一个常用的命令是 M-x auth-source-forget-all-cached. Auth source可能会把你在Emacs中的认证关系搞混乱了,执行这个命令会清空所有的缓存认证信息. in Emacs; use this command to forget all the cached details.

13 Automatic Jabber Login

下面有一个很常见的工作流: 用jabber.el登录Google Hangouts/Chat.el.

假设有这么一个jabber账户:

(setq jabber-account-list
      '(("<your-gmail-email>"
         (:network-server . "talk.google.com")
         (:port . 443)
         (:connection-type . ssl))))

当你执行 M-x jabber-connect 后,如果顺利话,Emacs要求你输入密码. 如果你不想每次都输入密码,你可以以加密的方式存储密码并且让Emacs自动为你输入密码.

为了做到这一点,我们需要一个 .authinfo 文件,还要通过某种途径告诉Emacs授权文件的位置. 默认情况下Emacs会尝试 ~/.authinfo 等几个地方,不过我比较推荐对授权文件进行加密并将之纳入源代码管理中. 你可以通过设置变量 auth-sources 的值来告诉auth-source去哪些地方查找授权文件:

(setq auth-sources
      '((:source "~/.emacs.d/secrets/.authinfo.gpg")))

你需要根据实际情况修改上面的路径. 下一步,创建这个授权文件然后添加下面一行内容:

machine gmail.com login <your account name> port xmpp password <your secret password>

<your account name> 替换为你的用户名(只需要用户名,例如是填johndoe而不是johndoe@gmail.com). 将 <your secret password> 替换为你自己的密码,然后保存该文件并选择之前创建的密钥进行加密.

确定已经设置了 auth-sources 变量的值后,再运行一次 M-x jabber-connect. 如果你的设置无误的话,Emacs会解密你的 .authinfo.gpg 文件(若Emacs没有存储密钥到内存中的话,还会提示你输入你的保护密码),然后根据主机名与用户名从 .authinfo.gpg 文件中找出对应的密码,发送給Jabber.

如果出错了,请参见上面 Debugging Authentication Issues 部分的内容.

同样的,你还可以将这种方法应用于你的email,应用于TRAMP(若没有使用SSH密钥的话)以及其他类似的场景中. Emacs会将密钥存储在内存中并且自动用它来进行加解密,而不会一边又一边的要求你输入保护密码.

另外, auth-sources 变量支持多中校验来源. 你甚至可以可以使用你操作系统中的keychain/agent作为密钥的来源.

14 Conclusion

你的Vogon poetry是安全的,这真是一个好消息. 如你所见,借助GPG以及Emacs的认证机制,可以使得大多数的认证过程变得自动化. EasyPG 与 Auth Sources是两个值得学习的强力工具. 事实上,我这里不过是提到了一点皮毛. 每个人都可能有自己独特的相关配置,所以如果你有什么有趣的,能够节省时间的流程,请告诉我.