使用 age 加密

Author Avatar
EpLiar 3月 03, 2020
license Anti%20996 blueLast Updated: 20-03-12

国内的通讯工具并不安全[1],尤其是微博等等工具上 404 已经成为家常便饭的时候,想要安全的和对方说一件事会变的尤为困难。在你没有办法使用国外通讯工具时,你又想给对方表达可能比较敏感的信息,那么你需要一个加密工具,避免中间人获取你想表达的信息。

本文将详细讲解使用 age 来加密数据。

关于 age

age 是 Actual Good Encryption 的缩写,是一个轻量且简单的命令行非对称加密工具,加密过程中会用到公钥和私钥。非对称加密原理是用公钥加密的信息,只能用私钥解密,通常用于通信。用私钥加密的信息,只能用公钥解密,通常用于数字签名,告知对方文件由私钥所有者本人所发出。

age 使用 Go 语言编写,并开源在 GitHub。还有一个使用 ruby 编写的版本 rage,有兴趣可以去看看。

基础知识

阅读本文前,我假定你有一定的命令行水平,至少知道打开命令行窗口,知道当前工作路径。否则,你可能需要在学习的时候依赖搜索引擎。你只要会基本操作就能照着这篇文章学会使用 age。如果你是有一定命令行使用基础的人,请直接跳转下载 age

cmd / 终端

age 是个命令行工具,在 Windows 下需要在 cmd 里运行,macOS 则是终端。按住 Windows 键不松开再按 R 键,会弹出运行窗口,输入 cmd 点击确定,就能运行 cmd。macOS 直接搜索终端即可 (部分用户可能会使用 iTerm2 等第三方终端工具,但相信使用了的用户也不会看这一段基础知识)。

cmd

cmd 是一个黑色的窗口,> 号前面是当前工作路径,如果你需要切换当前工作路径到 age 所在的目录 (后面会用到。如果你不想一直切换,可以把 age 添加到 path ,这会省下很多时间),可以使用 cd 命令来切换 (格式为 cd + 路径)。比如你要切换到 C:\Program Files 这个目录,你就可以这么输入:

$ cd C:\Program Files

手输路径会非常麻烦,你可以点击文件夹窗口的地址栏,复制文件夹地址后粘贴。但是,cmd 默认的起始路径是在 C 盘,如果你需要去其他分区下,需要先切换盘符,再使用 cd 命令。例:我要去到 D:\Program Files

$ D:
$ cd D:\Program Files

先输入盘符加冒号 (冒号应该是半角,如果你开启了中文输入法,冒号将是全角,关闭之后就是半角),回车后切换盘符,然后再使用 cd 命令。

cd

以下所有的命令前面都会有个 $ 符号,这是代表着在命令行的环境下,不带 $ 的就不是命令了。比如下图是 Windows 系统下的 Git Bash。

git bash

如果你电脑上已经有了 Git bash,或者你即将因为手动编译而下载安装好了 Git,那么你可以忽略 cmd 繁琐的 cd 命令,直接在你想要去的文件夹右键,会有 Git bash here。

git bash here

命令行会在前面带上一个 $ 符号 (虽然这个符号不起作用,也删不掉,只是提示你在命令行下),所以对着本教程的时候就不要把 $ 号一起输入进来了。哪怕你在 Windows 的 cmd 下,也不要输入。

如果你是复制了教程中的命令,在 cmd (或者是 powershell) 下点击鼠标右键就能粘贴在命令行里;如果你是 Git Bash 或者其他系统的 Bash, zsh 等命令行工具,可以使用鼠标右键粘贴。

添加 path

将 age 所在的路径添加到 path 里,将可以在任意工作目录下运行 age。

如果你在 Windows,下载 age 后希望在各个工作目录都能运行 age,可以将 age 的路径添加到 PATH 里。右键计算机 (此电脑) / 在此电脑窗口里右键 → 属性 → 高级系统设置 → 环境变量 → 双击系统变量的 PATH。如果你是 Win10,新建并粘贴 age 所在的路径即可;如果你是 Win7,在后面输入一个半角分号后粘贴。添加完成后,一路点击确定来关闭。

add path

如果你在添加 Path 的时候 cmd 是运行的,那你需要重新打开 cmd 才会使更改后的 Path 生效。

如果你是 macOS 等 unix 系统,在 age 的目录下,执行 pwd 命令来获取当前目录的绝对路径 (Windows cmd 下 > 符号前就是当前工作路径,但是 Git bash 的 pwd 结果不太适合直接添加到 PATH 里)。如果你在其他目录,先切换到 age 的路径再执行 pwd 命令。获取到绝对路径后 exportPATH 变量里。

$ pwd
/Users/epi/age
$ export PATH="$PATH:/Users/epi/age"

以上是我在私人电脑上的执行结果,可以参考示例代码来举一反三。另外 export 在你关闭终端窗口后就会失效,如果你需要它一直存在,需要将它写进 .bashrc 里 (zsh 用户是 .zshrc)。

$ echo 'export PATH="$PATH:/Users/epi/age"' >> ~/.bashrc
$ echo 'export PATH="$PATH:/Users/epi/age"' >> ~/.zshrc

Git bash 和 cmd 的差异

Git bash 的字体会圆滑一些,而且你可以用 tab 键快速补全 (cmd 也有,bash 更优秀一些)。

cmd 要执行当前目录下的可执行文件,直接输入名字就行了,但 bash 需要加上 ./(. 代表着当前目录,这么做是为了区分当前目录还是 path),比如 ./age

bash

文章中提到的命令

  • cat 将文件的内容输出到标准输出。

  • echo 打印内容。

  • cd 切换工作目录。

  • ls 列出当前路径的内容,cmd 下是 dir

下载 age

前面说到 age 是个轻量的命令行工具,可以免安装直接使用。下载的方式有两种:直接下载可执行文件,或者是下载源码后手动编译。

下载可执行文件

打开 age 的 GitHub 仓库: https://github.com/FiloSottile/age ,在 Releases 页面下载对应平台的压缩包解压后即可。

age releases

下载源码后手动编译

该方式需要使用 Git 和 golang。如果你的机器上还没有,可以下载安装。

golang 中国镜像地址: https://golang.google.cn/dl/

安装步骤略,一路点击下一步就行了。虽然安装过程会有英文,但如果这一步都需要截图写到教程里,那你可能不太适合本教程。

$ git clone https://filippo.io/age && cd age
$ go build -o . filippo.io/age/cmd/...

使用 golang 编译会同时下载 age 的依赖,如果网络比较魔法[2],则推荐直接下载 release 的可执行文件。虽然网络魔法的话 release 也下不动。

编译 age 需要 Go 1.13 以上的版本,直接在官网下载则不用考虑这个提示。

Homebrew

macOS 上有 brew 包管理器的话,可以直接从 brew 安装,安装的时候会下载 age 的依赖 go。

$ brew tap filippo.io/age https://filippo.io/age
$ brew install age

ArchLinux

$ sudo pacman -Syu git go-pie
$ git clone https://aur.archlinux.org/age.git
$ cd age
$ makepkg -si

go-pie 和 go 是冲突的。如果你的机器上已经安装了 go,直接克隆源码进行编译即可。

使用 age

以下命令假定你已将 age 的路径添加到了 path 或使用的是 cmd 且在 age 的目录下。如果你使用的是 bash 且没有添加 path,参照 Git bash 和 cmd 的差异

生成密钥对

下载好的 age 压缩包解开后会有 ageage-keygen 两个文件,首先要执行 age-keygen 来获得密钥对。同时为了方便下次使用,我们将私钥存在文本文件里。

下面的执行结果是我同步操作时的结果,以作为例子。

$ age-keygen -o key.txt
Public key: age1447gr3j9cex96y45manz3sp6jx3sw3vwftltwx7hty6dcqjtjprq8satdy
$ cat key.txt
# created: 2020-03-03T12:49:31+08:00
# public key: age1447gr3j9cex96y45manz3sp6jx3sw3vwftltwx7hty6dcqjtjprq8satdy
AGE-SECRET-KEY-1XT0A0AFQ9CV63X552JS6FX4M36ZSJW36S80J6U7QVVS58H8YAMVQRZTU8Z

这时候就能看到,公钥为 age1447gr3j9cex96y45manz3sp6jx3sw3vwftltwx7hty6dcqjtjprq8satdy,私钥保存在了名为 key.txt 的文本文件里 (你可以起一个你喜欢的名字,如:epi.txt 等),这时候你可以将公钥发送给即将通讯的人。

当某天密钥丢失的时候,你可以再执行一次 age-keygen 来生成新的密钥对。此处我们再生成一对,当作第二个人的密钥。

$ age-keygen -o key2.txt
Public key: age1h4cq2wxdys6xnqgnrp85qzr9lj3z3ze45f32gcuy500z06rv49tslz7fr5

加密文件

此处我们假定 Alice 和 Bob 要进行加密通信,key.txt 为 Alice 的密钥,key2.txt 为 Bob 的密钥,Alice 要给 Bob 发送一句 "Hello"。

依据上文可以得到 Bob 的公钥为 age1h4cq2wxdys6xnqgnrp85qzr9lj3z3ze45f32gcuy500z06rv49tslz7fr5,所以 Alice 给 Bob 发送 "Hello" 的命令为:

$ echo "Hello" | age -r age1h4cq2wxdys6xnqgnrp85qzr9lj3z3ze45f32gcuy500z06rv49tslz7fr5 -o hello.txt.age

这里的 -r 为接收者的公钥,-o 是将加密的内容指定加密后输出的文件。

age 的输入方式有文件和 stdin,使用 echo 就是从管道把文本传给 age。假定 Alice 的消息是已经存在了 hello.txt 里,那么我们就不需要 echo 了,直接指定输入文件即可。

$ age -r age1h4cq2wxdys6xnqgnrp85qzr9lj3z3ze45f32gcuy500z06rv49tslz7fr5 -o hello.txt.age hello.txt

解密文件

解密文件比较简单,因为对方用了你的公钥来加密,解密的话只需要用到本地存储的私钥就可以了。

Bob 收到了 Alice 发来的加密文件 hello.txt.age,将要解密。根据上文 Bob 的私钥存储为 key2.txt,解密的选项为 -d,指定密钥的选项为 -i,没有指定选项就是要解密的文件了。

$ age -d -i key2.txt hello.txt.age
Hello

当然,如果加密的是其他非文本文件,则直接输出到 stdout 就不太合适了,你可以通过 -o 来指定输出的文件名。解密之后你可以双击打开它,cat 只是用来做示例。

$ age -d -i key2.txt -o hello.txt hello.txt.age
$ cat hello.txt
Hello
decrypt

多个接收者

如果有多个接收者,使用 -r 来指定多个密钥即可。

$ age -o example.jpg.age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \
    -r age1lggyhqrw2nlhcxprm67z43rta597azn8gknawjehu9d9dl0jq3yqqvfafg example.jpg

此处的 \ 是为了避免过长而使用,使用后可以换行的同时而不执行,增加可读性。可以不照抄。

其他方式加密

密码 (不推荐)

age 支持通过密码来进行加密,适合面对面说好密码的情况,否则非常不安全[3]

密码支持手动输入,直接按下回车 age 会使用随机单词组合生成一个。

$ age -p hello.txt > hello.txt.age
Enter passphrase (leave empty to autogenerate a secure one):
Using the autogenerated passphrase "squirrel-situate-rug-equip-dwarf-check-evolve-ghost-style-galaxy".

目前使用 Homebrew 安装的 age 在输入 passphrase 时留空不会自动生成随机密码,已经给作者提 issue

ssh 密钥

你可以用本地已存在的 ssh 密钥进行加密,但不支持 ssh-agent。

$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZDRcvS8PnhXr30WKSKmf7WKKi92ACUa5nW589WukJz [email protected]
$ age -r "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZDRcvS8PnhXr30WKSKmf7WKKi92ACUa5nW589WukJz" example.jpg > example.jpg.age
$ age -d -i ~/.ssh/id_ed25519 example.jpg.age > example.jpg

可能遇到的问题

不是内部或外部命令 / command not found

你需要将 age 所在的目录添加到 path 里,具体请参照添加 path

解密后文件乱码

这个问题通常会出现在 Windows 和类 Unix 系统间,文本文件所使用的文字编码不同,非文本文件不受影响 (如 .zip .docx)。如果你在 Windows,使用记事本保存的时候将编码设置为 UTF-8。如果你使用的是 Sublime,可以安装 ConvertToUTF8 解决。

文件不能在 32 位机子上运行

这个就得依赖手动编译了,因为 64 位的机器默认会编译成 64 位,releases 也是 64 位的。但是编译 32 位的 age 很简单,你只需要在 32 位的机器上下载源代码编译即可。或者你已经有一台 64 的机器,可以编译了把源文件拷贝过去。

$ set GOARCH=386
$ git clone https://filippo.io/age && cd age
$ go build -o . filippo.io/age/cmd/...

后记

写本文用了一定的时间,但是无法保证覆盖到所有可能遇到的问题。如果你详细阅读本教程后无法学会,可以在 B 站看一下视频演示,也可以在下方评论,收到评论后我会回复并考虑更新本文。


1. 2 月 19 日因疫情防控工作出现漏洞,一夜之间济宁所有机关单位,社区,中小学微信群被解散。
2. 魔法指网络比较慢或被禁止,大部分是访问海外网络时。
3. 在通讯工具上公开密码相当于没加密。

CC BY 4.0
本文链接:https://epliar.com/articles/use-age-to-encrypt/