最近有需要在 Github 上配置 SSH 和 GPG,因此,将过程记录下来形成本文。没啥技术含量,就是一个记录。我这里使用的主机环境是 Ubuntu 22.04 LTS 和 Windows 22H2 build 22621。
无论是 SSH 还是 GPG,都是对于密码学(编码学)的应用。更进一步,它俩都使用了非对称加密方式。我对于加密也不是很懂,下面列出一些常见概念:
- 对称加密:在加密和解密时使用的是同一个秘钥
- 非对称加密:加密算法需要两个密钥来进行加密和解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)
- CA:Certificate Authority,证书授权中心 / 电子认证服务机构,受公众信任足够权威的第三方机构,负责管理和签发证书的。
- CA 证书 = 数字证书:经过 CA 认证的证书,包含 签证机关的信息、证书拥有者信息、证书拥有者的公钥、权威机构的签字和有效期 等信息
- 指纹 = 摘要 = 哈希值 = 杂凑值
- 密钥能力 = 密钥用途
SSH
SSH 为 Secure Shell 的缩写(虽然名字中有个 Shell,但他实际并不是 Shell),由互联网工程任务组(Internet Engineering Task Force,IETF)的网络小组(Network Working Group)所制定一个网络协议。
SSH 的经典用途是登录到远程电脑中执行命令。除此之外,SSH 也支持隧道协议、端口映射和 X11 连接。借助 SFTP 或 SCP 协议,SSH 还可以传输文件。
SSH 的详细介绍具体参考:Network 之六 SSH、SSL、OpenSSH、OpenSSL、LibreSSL
SSH 只是一种协议,存在多种实现,既有商业实现,也有开源实现。目前,OpenSSH 是最流行的 SSH 的开源实现,而且成为了大量操作系统的默认组件。SSH2 通常指 SSH Communications Security, Inc. (http://www.ssh.com) 实现的 SSH 协议版本 2 的专有软件名字。
安装
目前,SSH 已经成为了类 Unix 系统的标配组件,直接在 Ubuntu 终端中输入 ssh -V
就可以查看 Ubuntu 自带了 ssh 客户端的版本;同样,从 Windows 10 1803 版本开始,微软也提供 OpenSSH 工具,直接在 Windows Terminal 中(CMD)输入 ssh -V
就可以查看当前系统中的 SSH 版本。
默然情况下,Ubuntu 和 Windows 都没有了提供 SSH 的服务端。如果需要服务端,需要自行进行安装。Ubuntu:sudo apt-get install openssh-server
;Windows:设置 → 应用 →可选功能 → openssh-server
,具体参考:Network 之六 SSH、SSL、OpenSSH、OpenSSL、LibreSSL。
生成 KEY
生成 KEY 的过程在 Ubuntu 和 Linux 上并没有区别。需要注意的是,SSH 支持的加密算法有好几种,根据需要选择一个合适的即可。此外,Github 推荐 ssh-keygen -t ed25519 -C "your_email@example.com"
,但是在一些旧系统并不支持 ed25519 这个算法。我这里选择使用 RSA 算法。
生成的 KEY 的存放位置一般默认,直接回车即可(如果要生成多个 KEY 的话,这里就可以指定不同的名字来区分了)。至于密码,看个人需要,可以选择直接回车,从而不设置密码。然后,SSH 就会列出我们生成的 KEY 文件了。
Linux 系统内置有 Keyring机制,可以方便查看我们的 SSH 密钥。一般桌面都有对应的 GUI 程序,KDE 上有 KDE 钱包,GNOME 和其他桌面上叫做密码和密钥。
Keyring 参考:https://zhuanlan.zhihu.com/p/128133025?from_voters_page=true
部署 GITHUB 及 GITEE
经过上面生成 KEY 之后,在我们指定的目录下就会有 id_rsa
和 id_rsa.pub
这两个文本文件。其中,id_rsa
是私钥,需要我们保存好,id_rsa.pub
是公钥,把公钥内容添加到 GITHUB 及 GITEE 即可。
注意,在将 KEY 添加到 GITHUB 或 GITEE 时,需要验证我们对应的 GITHUB 或 GITEE 的账户密码。
使用及效果
配置好我们生成的 SSH 公钥之后,就可以选择使用对应仓库的 SSH 方式访问仓库了。需要注意,第一次 SSH 连接,会有类似的提示:“The authenticity of host ‘github.com (20.205.243.166)’ can’t be established.xxxxxxx.This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?”。这里选择 yes 即可。
每次本地 Commit 代码并推送到 Github 仓库或 Gitee 仓库后,在 SSH 的配置页面上都会显示我们最近有没有使用它。
GPG
GPG 又称 GnuPG,全称 GNU Privacy Guard,是一个遵照 OpenPGP 协议的用于加密、数字签名以及认证的软件。它是 PGP(Pretty Good Privacy)的开源实现,PGP 则是 Symantec 公司的专有软件。
GPG 的详细介绍具体参考:使用 GPG Key 来构建签名、加密及认证体系 和 简明 GPG 概念
在数字世界,我们经常需要进行邮件加密、数字签名或者登陆认证等操作,GPG 就是这样一个既可以方便我们管理公私钥,又可以随时满足我们需求的密钥管理工具。GPG 的用途要比 SSH 登录密钥丰富得多。
简写 | 能力(Capability)/用途(Usage) | 说明 |
---|---|---|
[C] | Certificating | 认证其他秘钥、给其他秘钥签名。类似于 SSL/TLS 根证书 |
[S] | Signing | 签名。例如,给文件添加数字签名,邮件签名,git commit 签名 |
[A] | Authenticating | 身份验证、鉴权,例如,SSH 登陆 |
[E] | Encrypting | 加密。例如,消息加密,文件加密 |
一个 GPG 密钥对之所以可以有这么多能力,是因为它本质上是若干密钥对的集合,只不过它们被封装到了一起。所有子密钥的有效性,都来自于主密钥的认证。子密钥可以在没有主密钥的情况下单独使用。
- 主私钥必须有 认证 [C] 这个能力,且这项能力只能属于主私钥。
- 主私钥可以同时拥有 认证 [C]、签名 [S]、身份验证 [A] 三项能力。
- 子私钥可以同时拥有 签名 [S]、身份验证 [A] 两项能力。
- GPG 的建议创建一个拥有 加密 [E] 能力的独立子私钥。
- 如果子密钥被泄露的话,可以只吊销子密钥。子密钥可以单独使用,但是,无论是那种用途,它都是由主键签名并同时传输的。这种做法允许自行撤销子密钥,同时保持主密钥有效。
从图中可以看出来,整个“密钥串”只有一张吊销证书,一旦这张证书发布,主密钥即被吊销,连带着子密钥一并吊销。那子密钥丢失了怎么办呢?GPG 不允许用户生成子密钥的吊销证书,而是把变更都放在唯一的公钥中,简洁且不易出错。你只需要编辑“大”密钥,将子密钥单独吊销,然后重新发布公钥即可,这样大家就都知道了。
实际上子密钥的公钥是存在的,也可以导出,但 GPG 为了防止用户误用,把这项功能藏得很深。毕竟,如果子密钥的公钥也单独使用,那就跟自己设计一个证书信任链没什么区别了。我们在实际使用中,导出的“公钥”实际上是一组公钥,其中就包括了被主私钥【认证 [C]】后的各个子公钥。
与 TLS 基于集中式的信任链不同,GPG 并不搞集中式,虽然开源世界中有不少 GPG 公共服务器组成的【公钥服务器池】(Web of Trust),但 GPG 将信任与否的决定权交给用户。OpenPGP 提供的开放的公钥服务器池地址是 https://keys.openpgp.org/,用户可以自由上传自己的公钥,方便他人知悉。世界上有两种密钥信任体系:
- GPG:相信你所相信的人(Web of Trust)。 简单来说,就是大家都把自己的公钥放到一个互联网上(例如,GPG 提供的 https://keys.openpgp.org/),好让别人都知道自己。这样在双方通信的时候,只要使用对方的公钥验证信息通过就可以确认对方身份。
- TLS:相信权威(CA)。 CA 的根证书一般都已内置于操作系或浏览器中,根证书是无条件信任的。因为信任根证书,因此,也要信任根证书认证的其他证书。
安装
对于大多数 Linux 系统发行版,默认都提供了在线安装选项,例如 Ubuntu:sudo apt-get install gnupg
,选择在线安装是最简单的;对于其他系统,GnuPG 官网提供了多个平台的预编译二进制文件,下载地址是 https://www.gnupg.org/download/。
对于 Windows 用户,可以选择 GUI,我比较喜欢命令行的简洁 ,选择了安装纯命令行。注意,最的版本是 2.x,不要选择旧版,因为他们的参数互相不兼容。安装好之后,直接使用命令 gpg --version
即可查看对应的版本。
Windows 系统上 GUI 版,网友写了详细的过程 https://blog.csdn.net/u011174139/article/details/120139497
生成 KEY
生成 KEY 的过程在 Ubuntu 和 Linux 上并没有区别。需要注意的是,GPG 支持的加密算法有很多,但是,GITHUB 及 GITEE 并不是全部都支持。Github 支持 RSA、ElGamal、DSA、ECDH、ECDSA、EdDSA;Gitee 没找到官方说明。我这里选择使用 RSA(GitHub 推荐使用 4096 位及以上的以 RSA 协议的 KEY),直接输入命令 gpg --full-generate-key
,然后回车,其他步骤见下图。
其中,第五步需要注意,这里有可能是弹出 GUI 的对话框,让输入一个密码(第二次输入用于确认密码),来保护我们上面填写的用户身份(UID,包含全名(一般是实名)、邮箱地址(用 < > 包括)、注释(用 ( ) 包括),例如,上图中的ZCShou (zcs) <72115@163.com>
),界面如下
- 一个密钥可以有多个 UID,方便不同场合使用。
- UID 与哪个子密钥无关,UID 是作用于整个密钥的。
- UID 可以随时添加,但已有的 UID 不能修改,只能单独吊销。
- UID 单独吊销后,只需要重新发布公钥即可
Linux 系统内置有 Keyring 机制,可以方便查看我们的 GPG 密钥。一般桌面都有对应的 GUI 程序,KDE 上有 KDE 钱包,GNOME 和其他桌面上叫做密码和密钥。
Keyring 参考:https://zhuanlan.zhihu.com/p/128133025?from_voters_page=true
部署 GITHUB 及 GITEE
-
查看私钥。使用命令
gpg --list-secret-keys --keyid-format=long
可以列出我们之前创建的秘钥 ID(图中红色框中的部分)。其中,sec 和 ssb分别是主密钥和子密钥(我们使用gpg --full-generate-key
命令默认就是创建一个主密钥和一个子密钥)
- KEY 指纹 是公钥的散列值(默认使用 MD5 算法),gpg 中的 fingerprint 与 SSH 的计算方法略有不同,SSH 中 fingerprint 是直接对 base64 的结果再计算 MD5 得来,而 gpg 则对合并后的 modulus 和 exponent 的二进制进行 MD5 计算而来。
- GPG 中使用 fingerprint 来作为 KEY-ID,用来标识一个 Key。Long ID 用 fingerprint 的后 16 位字符来表示,Short ID 则用 fringerprint 的后 8 位字符来表示。
主密钥和子密钥都是独立生成的,两者在生成时彼此之间并无依赖关系;但是在生成之后,GPG 用一个叫 Binding Signature 的东西把两种进行关联。简单来说就是主密钥对子密钥进行签名,声明自己对子密钥的 Owner 关系;同时子密钥也对主密钥进行签名,声明自己对主密钥的 Member 或 slave 关系。RFC 4880 中对此有解释如下:
-
查看公钥的具体内容。公钥由私钥导出,使用命令
gpg --armor --export 上面的私钥 ID
就可以导出公钥。
直接使用gpg --list-keys
就可以查看公钥的基本信息。其中,pub 和 sub 分别是主公钥和子公钥
注意,如果有多个 GPG 密钥,则会显示多组
-
将以上公钥(
-----BEGIN PGP PUBLIC KEY BLOCK-----
和-----END PGP PUBLIC KEY BLOCK-----
以及它俩之间的 KEY 内容)内容添加到 Github 和 Gitee 上去。添加方式非常简单,在他们的个人账户设置界面中,有专门添加 KEY 的地方。
注意,在将 KEY 添加到 GITHUB 或 GITEE 时,需要验证我们对应的 GITHUB 或 GITEE 的账户密码。
配置 GIT
-
配置 Git 使用公钥检查提交签名。全局配置命令:
git config --global user.signingkey GPG-KEY-ID
,其中,GPG-KEY-ID 就是gpg --list-secret-keys --keyid-format=long
列出的 KEY 的名字。
-
开启自动签名。全局配置命令:
git config --global commit.gpgsign true
,针对单个仓库命令(要在仓库目录下执行):git config commit.gpgsign true
。如果这里不配置,在使用git commit
时,需要使用-S
参数指定签名。 -
在 Windows 上需要显示指定 GPG 程序。全局配置命令:
git config --global gpg.program "C:\Program Files (x86)\gnupg\bin\gpg.exe"
。如果这里不配置,Commit 代码时会报错:gpg: skipped "xxxxx": No secret key
。注意将以上命令中换为自己的安装路径。
使用及效果
正常配置好上面的 GIT 之后,每次我们在本地 Commit 代码,GIT 都会自动调用 GPG 来给我的 Commit 进行签名,我们完全感觉不出有与之前有和变化。可以使用 git log --show-signature -1
来查看签名
当我们正常在 GITHUB 及 GITEE 部署好 KEY 并且配置好 GIT 之后,每次本地 Commit 代码并推送到 Github 仓库或 Gitee 仓库后,对应的 Commit (在 GITHUB 或 GITEE 的 Commit 列表查看)就会显示一个验证标签。
gpg: can’t connect to the agent: IPC connect call failed
今天在提交代码时,提示 gpg: can’t connect to the agent: IPC connect call failed。这个是由于 gpg-agent
没有正常启动导致的。根据 官网说明,当我们用到 gpg 时,gpg-agent
会自动启动,但是我这里却没有,不知道为啥。解决方法也很简单,手动启动一下 gpg-agent
即可:gpg-agent --daemon --verbose
。
SSH 对比 GPG
- SSH(Secure Shell) 用于交互通信过程中的安全,是双向的。
- GPG(GNU Privacy Guard) 既可用于加密,也可用于签名,这些都是单向的。
- 私钥在 SSH 中被称为 private key,而在 GPG 中被称为 secret key。公钥则都叫 public key。
- 一般来讲,SSH 的公钥只有你的服务器知道,别人也不需要知道。GPG 的公钥则巴不得全世界知道,告诉大家“认准这个证书,谨防假冒!”
- 对于 SSH,建议一站一钥,万一丢了也好处理。对于 GPG,一把主钥+多个子钥即可。完全可以把 GPG 的子密钥 [A] 用于 SSH 登录。
参考
- https://blog.csdn.net/u011174139/article/details/120139497
- https://zhuanlan.zhihu.com/p/481900853
- https://zhuanlan.zhihu.com/p/137801979
- https://docs.github.com/cn/authentication/managing-commit-signature-verification/generating-a-new-gpg-key
- https://www.codercto.com/a/49711.html