2021年,用更现代的方法使用PGP(中)

安全使用

Posted by UlyC on January 18, 2021

世界上有两种密码:一种是防止你的小妹妹偷看你的文件;另一种是防止当局阅读你的文件.

​ —— Bruce Schneier《应用密码学》

2021年,用更现代的方法使用PGP(中)

上篇链接:

2021年,用更现代的方法使用PGP(上)

三、安全使用和备份

准备

为了安全性,建议在一台断网的Linux或者BSD系统上生成你的密钥对。

特别推荐使用 Tails (boum.org)发行版,系统自带gpg和paperkey 等工具, 可以确保全程断网操作, 同时此系统重启会擦除所有内容,还免去了擦除密钥的麻烦。 需要工具:

  • 一台电脑
  • 一个装有Tails系统的U盘0 , 使用它生成密钥
  • 一个已经全盘加密的U盘/TF 卡 1(推荐),或者智能卡 , 用来存储主密钥
  • 一个智能卡 (推荐) ,或者已经全盘加密的U盘/TF 卡 2, 用来存放子密钥,日常使用

备份策略

我的备份策略:

  • 主密钥只保留一份,离线。
  • 子密钥可以复制多份,通过U盘导入各个设备,专密专用, 日常使用推荐用智能卡(比如Yubikey),还能免去每次输密码的麻烦
  • 撤销凭证可以和主密钥放在一起备份一份, 另外单独备份一份(这样丢失密钥,起码还可以撤销)

主密钥备份建议备份在一个全盘加密的U盘中,然后放在一个绝对安全的地方。

备份介质:

智能卡

主密钥不建议导入智能卡设备,因为智能卡的使用场景是随身携带,随时取用,虽然智能卡中的密钥无法导出,但是随身携带增加了丢失的风险,主密钥一旦丢失,将会非常麻烦。

如果是土豪,当然导入智能卡中更好,因为智能卡中密钥无法导出,只不过这个智能卡不能再随身携带,而同样应该在一个安全的地方, 不到万不得已不再取用, 不过这样有些浪费,也是我不推荐的理由。

网盘存储

你可以将主私钥加密后上传到网盘或其他线上服务。

PaperKey

又是断网操作,又是非对称算法,还要好好保存一份私钥,这一套流程走下来你也发现了跟数字货币的相似性,很多备份方式都可以借鉴他们的思路,比如上面网盘存储就是数字货币热钱包的思路。

冷钱包很经典的一种方式,就是将私钥写/打印在纸上, 当然我们也可以借鉴,不过若你想将这一眼望不到头的私钥抄下来, 或者打印下来,将来需要恢复的时候再一个个输入进电脑,显然不现实。

image-20210113111654636

(示例私钥的一部分,用完即废,如果是你自己的私钥,打死也不要给别人看)

比如比特币, 私钥长这样:

5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss          # 这么短很容易抄写和输入

同样是非对称算法,为什么PGP的私钥就长这么多呢?

因为他们用的算法不同,比特币默认使用的是ECDSA的 secp256k1算法, 该算法只是用来签名和认证,并不用来加密(很多科普文章会说这是加密算法,比特币的算法也可以用来加密,这是错的,比特币之所以有时被称作加密货币只是因为它依赖了密码学中的非对称算法,并不是它能加密…),PGP默认的是RSA算法,可以同时用来签名和加密,前面说过目前RSA密钥长度不小于2048 bit才安全,而且PGP导出的私钥中不止密钥信息,还包含了全部的公钥信息,UID,子密钥信息,以及设置密码时的混淆。

Linux下有一个工具叫做paperkey, 可以用来消去私钥中 冗余的公钥信息,极大减少私钥长度,然后可以将精简过的私钥(base 16格式)打印出来,或者将Raw格式转换成二维码,打印出来。

注意:

  • 既然决定用PaperKey, 还是不要使用网络打印机了,

  • paperkey这个工具在Tails新版中是默认软件
  • paperkey 手册中推荐 恢复私钥时使用OCR扫描, 而大部分OCR服务都要联网, 请注意这点。
其他

密钥只是一段信息,理论上可以放在其他任何可以存储信息的介质中,例如光盘,隐写在图片中写入IC卡纹身,X光片背下来 等等等等,可以发挥你的想象力。

安全使用

请在你信任的电脑上使用子密钥,主密钥不到万不得已不要拿出来用,如果你将子密钥放在智能卡中使用,可以忽略这部分。

子密钥可以放在移动存储设备上直接使用,而无需拷贝/导入到电脑使用, 使用方法:

gpg --homedir [你的存储设备的路径]

四、进阶使用

使用其他算法

为什么安全?一节中 提到PGP支持很多算法,可是前面我们生成密钥时,只见到了很少的几种。

因为gpg还有一种隐藏模式—- 专家模式,生成密钥时可以使用

gpg --expert --full-gen-key
# 输出

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
  

就可以看到多出来不少选项,其中ECC算法 全称Elliptic Curve Cryptography 椭圆曲线密码算法。

上面我选了 9 , 继续

  Please select which elliptic curve you want
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256   
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1            # 比特币使用的算法

其中美国国家标准与技术研究院(NIST)系列椭圆曲线、Brainpool系列椭圆曲线、secp256k1都存在不同的安全风险,不建议使用。

可以发现这里少了(2), 其实这里还有一些隐藏算法没有列出,可通过如下命令查看

gpg --list-config --with-colons curve

# 输出
cfg:curve:   cv25519;ed25519;nistp256;nistp384;nistp521;brainpoolP256r1;brainpoolP384r1;brainpoolP512r1;secp256k1

上面缺少的(2)对应的就是ed25519 ,是一种签名算法,你选择 (1)时, 主密钥用来签发和签名 用的就是ed25519,自动生成的用来加密的子密钥 算法 是cv25519 。

RSA VS ECC

ECC算法比RSA的优势在于,在同等强度下,ECC的密钥长度要小的多,性能也会好一些。 RSA算法的PGP私钥 通过paperkey精简过后一般还会有50+行HEX数据,如果使用的是ECC算法生成的话, 可以减到8行以内,手抄完全没问题。

RSA算法的优势在于大部分硬件设备的兼容性比较好,比如 YubiKey 5 支持 RSA 4096,但不支持 Curve 25519。而且多数设备都对RSA算法提供了硬件加速。

PS:

查阅资料时发现 ,中文博客里被很多人抄来抄去的一句话:

ed25519 加密解密很快,生成时间短而且安全性更高,rsa 则加密解密稍慢,生成时间长,安全性没有 ed25519 高,只是 rsa 基本都是默认,所以用的人更多,但是建议转换为 ed25519, 网站软件现在基本都支持了.

这句话是 错的, ed25519是 EdDSA 算法的一种,只是一种签名算法, EdDSA 全称Edwards-curve Digital Signature Algorithm,爱德华椭圆曲线实现的数字签名算法。

上面的话多出现在替换SSH默认的RSA算法为ed25519的文章中出现。其实SSH协议中的非对称算法 并不是用来加解密信息的,而只是用来认证,正确的说法是ed25519签名和认证的速度很快。

再者, 不提密钥长度说安全性都是耍流氓 ,RSA 4096 的安全强度是要 好于 ed25519 的。

追加UID

uid 即 user id , 由三个部分组成:

  • 全名(现在的话网名即可)
  • 注释(用 ( ) 包括)
  • 邮箱地址(用 < > 包括)

UID的性质:

  • 一个密钥可以有多个 uid,方便不同场合使用。
  • uid 与哪个子密钥无关,uid 是作用于整个密钥的。
  • uid 可以随时添加,但已有的 uid 不能修改,只能单独吊销。
  • uid 单独吊销后,只需要重新发布公钥即可。

一般来说,操作UID只有主密钥有权限操作, 后面会提到UID可以是伪造,然后提交到服务器的。

gpg --edit-key {keyid/uid}    


gpg> adduid     # 进入交互界面后 输入  help  可以查看支持的操作

# 输入你要追加的信息

使用UID的场景有哪些呢? 如果你使用一个不常用的邮箱作为你的github/gitlab账号,你主要的邮箱生成的PGP 密钥就不能用来签名了。

这时候为了保护隐私 且 只要管理一个密钥,就可以 在 Github设置里把 Keep my email addresses private勾上,将为你生成的随机邮箱添加到 uid中, 这样就只需要管理一个PGP密钥,可以同时为你不同的Git账号签名。

添加头像

跟添加UID差不多, 在gpg交互 界面 输入 addphoto 就可以, 想要查看的话 输入showphoto

使用PGP为git commit 签名

只要你PGP的uid包含 git config 中的邮箱, 使用

git commit -S -m your commit message

即可签名。

使用PGP 进行SSH

生成 认证(A)用子密钥

gpg --expert --edit-key {keyid/uid}                                   ## 使用专家模式, 不然没有认证的选项


gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
Your selection? 8                                                   ## 选8, RSA, 自定义权限

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt                               ## 这里显示默认有Sign和Encrypt两种权限

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S                                                   ## 关闭Sign

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E                                                   ## 关闭Encrypt

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A                                                   ## 开启Authenticate

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q                                                    ## 退出
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y                                             ## 有效期
Key expires at Tue Jan  7 11:33:54 2020 CST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa2048/7DEFA5351BCE3C55
     created: 2019-01-07  expires: 2021-01-06  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa2048/2FCE923F8ECB63F6
     created: 2019-01-07  expires: 2021-01-06  usage: E
ssb  rsa4096/19D32A8839DCAA1F
     created: 2019-01-07  expires: 2020-01-07  usage: A
[ultimate] (1). hhhhh <h@mail.com>

gpg> save                                                            ## 保存

配置文件

编辑bashrc 文件, 将默认ssh 的agent替换为 gpg-agnet

#  ~/.bashrc

export GPG_TTY=$(tty)
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
echo UPDATESTARTUPTTY | gpg-connect-agent 1> /dev/null

编辑~/.gnupg/gpg-agent.conf文件,增加:

#  ~/.gnupg/gpg-agent.conf

enable-ssh-support

接着:

❯ gpg -k --with-keygrip    
/Users/root/.gnupg/pubring.kbx
-----------------------------
pub   rsa2048 2019-01-07 [SC] [expires: 2021-01-06]
      8A9FC025A44AA4824C1F4AE27DEFA5351BCE3C55
      Keygrip = BEFCCDFE36CC5442B888B8459265C68B60A4ABD2
uid           [ultimate] hhhhh <h@mail.com>
sub   rsa2048/0xF681DAEBBAB82124 2019-01-07 [E] [expires: 2021-01-06]
      Keygrip = 422922ACFD099E79863D93B93333528F225C90FC
sub   rsa2048/0x501DEDC36BD409C8 2019-01-07 [A] [expires: 2020-01-07]
      Keygrip = 999A87A51CFE82DAA494BEB42F585051307F9E33

选择你新加的带有[A]标志的那个新的子密钥的 keygrip , 即999A87A51CFE82DAA494BEB42F585051307F9E33

加入到~/.gnupg/sshcontrol文件, 运行ssh-add -l, 查看是否已经加入。

然后

gpg --export-ssh-key   {keyid}! 

注意,这里不能用 uid ,不然会提示:

gpg: key "uid" not found: Unusable public key
gpg: export as ssh key failed: Unusable public key

这里只能填子密钥的 key id,这个例子里就是 0x501DEDC36BD409C8

输出的 ssh public key 放到你的服务器上的~/.ssh/authorized_keys中, 重启shell, 就可以连接了。

未完待续


知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。