SSH、GPG学习与使用

1 前言

记得第一次接触到SSH是在开始折腾博客那会,照着网上的教程一步步来设置Github环境、生成SSH key什么的,然后每次git push的时候就不用输密码了。
第二次接触到它是在买了VPS之后,听说大佬们为了增加安全性都是通过密钥登录的,这里用的也是SSH key
而接触到GPG是最近逛别人博客时,发现有好几个都留了个叫PGP公钥 的东西,如PRINNeoAtlantis的博客。正好印象中记得Github里好像有个GPG key,出于好奇于是学习了下相关知识,说不定以后用得到。

2 SSH

2.1 是什么

SSH(Secure Shell),一种加密的网络传输协议,来实现SSH客户端与服务器之间的连接。

SSH是每一台Linux电脑的标准配置。

众所周知,SSH主要用于远程登录;说它安全是因为采用了非对称加密,但也不是没有风险。由于具体的实现细节我没必要去关注,涉及到密码学一些知识也看不到,只求知道大概的原理和使用方法就行。

2.2 公钥和私钥

首先是这两个基础概念,非常重要

  • 私钥
  1. 非公开(废话),打死不交给别人
  2. 用私钥加密的数据只有对应的公钥可以解密
  • 公钥
  1. 公开
  2. 用公钥加密的数据只有对应的私钥可以解密

这不没区别么???好像真是这样,除了公钥和私钥是成对的、随便规定一个为公钥、那么另一个就叫私钥好了。数学上据说没区别,但是平常使用中,私钥的地位远远高于公钥;而且很多工具都设计成:私钥包含公钥信息,即私钥可以推导出公钥私钥包含公钥
所以使用中千万不要弄混了,一般带有pub字眼的为公钥(public key)。

2.3 SSH登录

梳理下利用SSH登录vps的流程吧,虽然个人理解的可能不太准确...

  1. 客户端向vps发起一个登录请求
  2. vps生成一串随机数,利用之前配置好的公钥(authorized_keys)进行加密,将加密后字符串传给客户端
  3. 客户端利用私钥(id_rsa)进行解密,将解密后的字符串外加一些别的(sessionKey之类的、我也不知道是啥)字符串;将整合得到的新的“摘要”用私钥加密,发给vps
  4. vps对“摘要”用公钥解密,通过解密得到的文本判断是否认证该客户端登录

可以看到整个过程充分利用了公钥和私钥可以互相加密与解密的特点,通常说公钥加密、私钥解密

2.4 常用命令

  • 首先得生成一对SSH密钥
    # Github帮助里就有
    ssh-keygen -t rsa -b 4096 -C "[email protected]"
    用默认值、按几下空格就生成了,passphrase不填(填了的话每次还得输一遍安全密码),毕竟用SSH keys的目的就是想偷点懒不必每次输入密码。
    注意密钥的位置默认是:
    ~/.ssh/id_rsa
    ~/.ssh/id_rsa.pub
    #也就是说和当前$USER有关,若为root,则在/root/.ssh/
    #若为xxx,则在/home/xxx/.ssh/
  • 若不是在本机生成的密钥(如从别的地方拷贝过来的),还要将SSH 密钥添加到ssh-agent
    # 注意.ssh文件夹的权限、所属用户组
    sudo -u $USER /bin/bash -c "sudo chmod -R 700 $HOME/.ssh" && \
    sudo -u $USER /bin/bash -c "sudo chown -R $USER:$USER $HOME/.ssh" &&\
    sudo -u $USER /bin/bash -c "sudo chmod 600 $HOME/.ssh/id_rsa.pub" && \
    eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa && \
    ssh -T [email protected]

如果已经把$HOME/.ssh/id_rsa.pub添加到了Github,那么运行下面的命令后应该就会出现类似下面的问候(当然用户名、邮箱之类的要配置好):

Agent pid 19103
Identity added: /home/zcp/.ssh/id_rsa (/home/zcp/.ssh/id_rsa)
Hi chengpengzhao! You've successfully authenticated, but GitHub does not provide shell access.

2.5 密钥管理

不知道多少人是每换一个环境(比如换台电脑、换个操作系统、换台VPS)就把上述的SSH keys配置流程重新走一遍的,然后保存了一大堆的私钥。固然,这样安全性比较高,但我更偏向于只使用一对密钥,生成之后好好保管着,然后要用的时候复制到相关环境里。
最近学shell脚本顺便就写了个自己用的一键配置Linux环境,我甚至把SSH公钥加密后的私钥都放到了Github Repository里,目的是尽可能减少本地管理的密钥数量。这里加密是利用GnuPG完成的。

3 GPG

3.1 是什么

刚开始分不清GPGPGP,以为有一个是写错了,后来才知道原来PGP代表Pretty Good Privacy,是一个加密用的商业软件;GPGGnuPG的简称,是一个开源软件、PGP的替代品。还有个叫OpenPGP的一套标准,大多数PGP软件都遵循它。 GPG可以用来实现非对称的文件加密、对数据进行签名等操作;这也是它最主要的两个用途,如GitHub里Verified的签名就是用它实现的:

3.2 密钥和子密钥

PGP中有密钥对和子秘钥的概念,如果我们只使用主密钥对,那么私钥泄露后只能吊销整个密钥,所以一般不使用主密钥,而是通过产生一系列用途各异的子秘钥进行操作。好像可以单独导出子秘钥,但公钥由于是公开的,所以主公钥、子公钥都是捆绑在一起的。 (试过只导出一个子公钥,结果和导出所有公钥的输出一模一样)
使用建议:主私钥不要放在网络上,平时只用子私钥操作,并且最好设定一个过期时间;一般用三个子私钥(A验证+E加密+S签名) 。


关于一些人建议将PGP key上传到一些key server,我是反对这种做法的,因为公钥服务器上的key无法删除,只能被吊销,而且可能暴露你的email等信息。而又几乎没有任何好处,谁会真正去key server上搜你的公钥?搜到的公钥安全性也没有保障;建议公开公钥到更加安全的地方。
服务器上的公钥更多的是利用gnupg的相互签署机制,即可以签署别人的公钥,即告诉其他人自己是信任这个人的公钥的真实性的;但说真的有多少人会真正用到这个功能呢,总之不推荐key server

3.3 常用命令

3.3.1 生成密钥

gpg --full-gen-key

选择因需求而异,我是默认类型、44096位、永不过期、用户标识、密钥安全密码。
生成完后会出现类似下面输出:

gpg: 密钥 404AAAD7FED2325E 被标记为绝对信任
gpg: 目录‘/home/zcp/.gnupg/openpgp-revocs.d’已创建
gpg: 吊销证书已被存储为‘/home/zcp/.gnupg/openpgp-revocs.d/9C0281B1DDCCD3289CE3B297404AAAD7FED2325E.rev’
公钥和私钥已经生成并被签名。

pub   rsa3072 2020-03-03 [SC]
      9C0281B1DDCCD3289CE3B297404AAAD7FED2325E
      uid                      zzzcp
      sub   rsa3072 2020-03-03 [E]

可以看出会自动产生一个用于加密的子密钥对

3.3.2 常见缩写含义

A    =>    Authentication
C    =>    Certify
E    =>    Encrypt
S    =>    Sign
?    =>    Unknown capability
sec  =>    Secret Key
ssb  =>    Secret SuBkey
pub  =>    Public Key
sub  =>    Public Subkey

3.3.3 添加子密钥对

#专家模式
gpg --expert --edit-key  xxxx # 进入GPG界面,接下来help看帮助,addkey加子秘钥
# 只有在专家模式下能够自定义密钥用途

生成后的输出:

sec  rsa4096/BF5738A17E62F3FC
     创建于:2020-03-04  有效至:永不       可用于:SC
     信任度:绝对        有效性:绝对
ssb  rsa4096/53BF89B0D716836D
     创建于:2020-03-04  有效至:永不       可用于:E
ssb  rsa3072/A11C5129AAE5BA77
     创建于:2020-03-04  有效至:永不       可用于:S
ssb  rsa3072/F63314C02344A273
     创建于:2020-03-04  有效至:永不       可用于:A
[ 绝对 ] (1). JiyoTomare (この、くそったれな世界に、精一杯愛をこめて) <[email protected]>
  • 重中之重
    生成完之后千万不要一激动按<Ctrl+C>退出gpg界面了,输入save正确的退出!!!

3.3.4 生成注销证书

密钥作废时使用(我没用过所以还不清楚具体怎么用),需要用到的时候再学吧

gpg --gen-revoke [ID]
#ID可以是邮箱或者是密钥标识的那一长串字符串

3.3.5 列出密钥

# 列出所有公钥、子公钥
gpg --list-keys --keyid-format LONG
# 列出所有密钥、子密钥
gpg --list-secret-keys --keyid-format LONG
# 更简洁的命令:
gpg -k # 列出公钥
gpg -K # 列出私钥

3.3.6 输出密钥

推荐分开输出,即每个子私钥保存一个文件,不混在一起

gpg --fingerprint #输出公钥指纹,用来核对公钥的可靠性
gpg --armor --output public-key.txt --export [ID]  #导出公钥
gpg --armor --output secret-key --export-secret-key [ID] #导出主私钥,注意安全性!!!
gpg --armor --output sign-subkey --export-secret-subkeys [ID]   #导出有[S]标识、签名用子私钥
gpg --armor --output encrypt-subkey --export-secret-subkeys [ID] #导出有[E]标识、加密用子私钥
gpg --armor --output authentication-subkey --export-secret-subkeys [ID] #导出有[A]标识、认证用子私钥
# --armor选项不启用,就会导出二进制格式文件

妥善保管自己的私钥!

3.3.7 删除密钥

#一般要先删除子私钥才能删除主私钥
gpg --delete-secret-keys [ID]
gpg --delete-keys [ID]
#如果想全部删除推荐直接删文件夹,即删除 $HOME/.gnupg

确保把所有数据都删除了。之后再就只导入子私钥了,主私钥妥善保管,一般不使用。

3.3.8 导入密钥

#从本地文件导入
gpg --import [密钥文件]
# 从URL导入
curl https://raw.githubusercontent.com/chengpengzhao/Zcp-s-PGP-Signatures/master/Zcp_PGP.pub | gpg --import

我导入完成后的输出:

/home/zcp/.gnupg/pubring.kbx
----------------------------
sec#  rsa4096 2020-03-04 [SC]
      77F37C33368AD0B5D52810D1BF5738A17E62F3FC
uid           [ 未知 ] JiyoTomare (この、くそったれな世界に、精一杯愛をこめて) <[email protected]>ssb   rsa4096 2020-03-04 [E]
ssb   rsa3072 2020-03-04 [S]
ssb   rsa3072 2020-03-04 [A]

可以看到信用等级是[未知],可以通过gpg --edit-key ID再运行trust命令调整。
#号说明缺失当前私钥,因为我为了安全没有导入主私钥

3.3.9 加密解密

# 加密:
# recipient指定接收者的公钥ID
gpg --recipient [ID] --output encrypt.txt --encrypt input.txt
# 也可以按喜好加上--armor选项等
# ***************************************
# 解密:
gpg --decrypt encrypt.txt --output decrypt.txt
# 虽然是常识性问题但还是再提一下,解密要用公钥对应的私钥!

3.3.10 签名

# 第一种方式,生成二进制签名文件
gpg --sign input.txt  # 当然也可以加上--output参数
# 第二种方式,生成ASCII格式签名
gpg --clearsign input.txt
# 第三种,签名和原文本分开(前两种的签名文件中包含了所有原文本,所以体积会比较大)
gpg --armor --detach-sign input.txt  #不加armor生成会二进制

当然也可以结合签名和加密,用自己的私钥签名,他人的公钥加密:

gpg --local-user [发信者ID] --recipient [接收者ID] --armor --detach-sign --encrypt input.txt

3.3.11 验证签名

# 注意签名在前,被签名文件在后
gpg --verify demo.txt.asc demo.txt

4 我的PGP keys

我把自己的身份验证方法放在了Github一个仓库里,所有的提交都是经过PGP key验证了的。
Zcp's PGP Signatures


前面介绍的GnuPGP主要在Linux环境下使用,Windows中推荐WSL或者用Gpg4win软件。总的来说我们使用PGP keys的目的就是:

  1. 供他人验证身份,来证实某消息确实出自自己之手、并且未被第三人修改过。
  2. 加密消息,通过他人公开的公钥能够向对方发送加密了的讯息,而只有持有对应私钥的他本人能够解密。
Author: zcp
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source zcp !
 Previous
さらば、霓虹
1 现在每次离开一个呆了一段时间的地方都会产生一些乱七八糟的感慨,与其望着一地行李发呆,不如写点什么,顺便做个阶段性的总结吧。 1.1 返程计划首先,这次离开的有些匆忙,受疫情影响大量航班都取消了,我先后买了海南航空
Next 
《1984》个人读书摘录
剧透警告 1 前言最近试着休息时尽量多看点杂书,不知不觉已经看完几本了。中文偏向于读一些引发人思考类型的,日文和英文因为读起来比较费劲还是读轻小说这种书有意思,不然根本读不下去。 看完的第一本是George Orwell的名作
  TOC