密码学之二 —— GPG、SSH
一、GPG
是什么?
-
GPG(GNU Privacy Guard)是基于 OpenPGP 协议的开源加密 / 签名工具链,并非单一的签名算法,而是将 RSA、ECDSA、Ed25519 等底层数字签名算法,与分层密钥体系、信任模型、密钥管理结合的完整解决方案 —— 它解决了纯算法层面 “密钥难管理、身份难验证、跨平台不兼容” 的问题,是开源社区、软件开发、文件分发场景中最常用的签名验证工具(如 Linux 发行版验证、Git 提交签名、开源软件包校验)。
-
GPG 不是 “发明了新的签名算法”,而是对 RSA、ECDSA、Ed25519 等底层数字签名算法的封装,并增加了:
- 分层密钥体系(主密钥 + 子密钥,降低核心密钥泄露风险);
- 信任模型(Web of Trust,验证密钥持有者的真实身份);
- 完整的密钥生命周期管理(生成、导出、导入、吊销、过期);
- 跨平台的签名 / 验签工具链(命令行 / 图形界面适配所有系统)。
-
GPG与PGP
PGP(Pretty Good Privacy)和 GPG 是同协议、不同实现的加密 / 签名工具,核心底层均遵循OpenPGP 密码学协议,二者的签名、加密逻辑完全一致,生成的签名 / 密钥文件互相兼容(GPG 可验证 PGP 签名,PGP 也可验证 GPG 签名);
核心差异在于PGP 是商业闭源的原始实现,GPG 是开源免费的替代方案,也是目前绝大多数开发者、开源社区的首选。
为什么?
-
分层密钥体系
采用主密钥 + 子密钥的分层设计,所有签名操作均由子密钥完成,主密钥可离线存储(冷备份)。- 主密钥(Primary Key),唯一标识身份,签署子密钥/证书,离线存储(U 盘 / 冷钱包)。主密钥仅用于 “管理子密钥”(签署、吊销子密钥),不参与日常签名 / 加密,即使子密钥泄露,可吊销子密钥并生成新的,主密钥仍安全,避免核心身份丢失。
- 签名子密钥 对文件 / 代码 / 邮件做数字签名 高 日常使用的设备(电脑)
- 加密子密钥 加密数据(非签名用途,可选) 高 日常使用的设备(电脑)
- 认证子密钥 SSH 认证 / 身份验证(可选)
-
密钥核心属性(生成 / 使用时必须关注)
- 密钥算法:GPG 支持 RSA、ECDSA、Ed25519(推荐 Ed25519,安全高效);
- 密钥长度:RSA 建议 4096 位,Ed25519 固定 256 位(安全级别更高);
- 过期时间:建议设置(如 1 年),避免永久密钥泄露风险;
- 用户 ID:绑定身份(如张三 zhangsan@example.com),便于识别;
- 密钥指纹:密钥的唯一哈希标识(40 位十六进制),用于验证密钥真实性(如D88E 0F8A 3773 8837 6A2A 86E3 F947 8044 9446 867F);
- ASCII Armor:将二进制密钥 / 签名转换为 Base64 格式的文本,便于传输(如邮件附件、网页发布)。
-
GPG 信任模型:Web of Trust(信任链)
GPG 不依赖中心化机构(如 CA 证书),而是通过 “信任链” 验证密钥身份:你验证 A 的密钥指纹后,标记 “A 的密钥可信”;A 验证 B 的密钥后,你可通过 A 的信任关系,间接信任 B 的密钥;核心:密钥指纹是信任的唯一锚点,验证指纹时必须通过线下 / 可信渠道(如作者官网、线下见面)确认,避免中间人攻击。
怎么用?
1、GPG 签名的完整流程(从密钥生成到验签)
阶段 1:生成 GPG 密钥对(核心步骤,仅需一次)
点击查看代码
#生成密钥
gpg --full-generate-key
# 列出本地所有GPG密钥
gpg --list-keys
# 输出示例(核心信息:密钥ID、用户ID、指纹)
/home/xxx/.gnupg/pubring.kbx
------------------------------
pub ed25519 2026-02-02 [SC] [expires: 2027-02-02]
D88E0F8A377388376A2A86E3F94780449446867F # 密钥指纹(核心)
uid [ultimate] Zhang San <zhangsan@example.com>
sub ed25519 2026-02-02 [E] [expires: 2027-02-02] # 加密子密钥
sub ed25519 2026-02-02 [A] [expires: 2027-02-02] # 认证子密钥
pub:主密钥(SC=Sign+Certify,签名 + 证书);
sub:子密钥(E=Encrypt,加密;A=Authenticate,认证);
密钥指纹:D88E0F8A377388376A2A86E3F94780449446867F(40 位,唯一标识)。
阶段 2:GPG 签名(两种核心类型,覆盖所有场景)
点击查看代码
#类型 1:明文签名(签名与内容合并,适合文本 / 代码)
将签名信息直接附加在文本末尾,生成新的 “签名 + 内容” 文件,适合邮件、代码提交说明等场景
# 对文件file.txt做明文签名,生成file.txt.asc(ASCII格式)
~> gpg --clearsign file.txt
# 对文本直接签名(输出到终端
~> echo "Hello GPG" | gpg --clearsign
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hello GPG
-----BEGIN PGP SIGNATURE-----
iHUEARYKAB0WIQRTRknnl5aEqIQZZnal9qKQn5fxzwUCaYF03QAKCRCl9qKQn5fx
z5V/AQDBjTn5XRAI4cJZZXNG4T5pbwcqjSDpOKwKFagC3zEjVQD/QPBrJHYzFuMg
c8fq6k4+cpTol83UFzy2guNyYK5E8QU=
=GqEC
-----END PGP SIGNATURE-----
#类型 2:分离签名(签名单独文件,适合二进制 / 大文件)
签名结果生成独立的.sig/.asc文件,原始文件和签名文件分离,适合软件安装包、ISO 镜像、视频等二进制文件:
# 对file.bin做分离签名,生成file.bin.sig(二进制格式)
gpg --detach-sign file.bin
# 生成ASCII格式的分离签名(便于传输),生成file.bin.asc
gpg --detach-sign --armor file.bin
核心区别:分离签名不修改原始文件,仅生成签名文件,是文件分发的主流方式(如 Linux 镜像的签名验证)。
阶段 3:GPG 验签(验证签名的真实性和内容完整性)
点击查看代码
前提:导入对方的公钥(仅需一次)
# 方式1:手动导入公钥文件(如对方提供的public.key)
gpg --import public.key
# 方式2:从GPG密钥服务器获取(通过密钥ID/指纹/邮箱)
gpg --recv-keys D88E0F8A377388376A2A86E3F94780449446867F # 密钥指纹
# 验证公钥(关键:核对指纹是否与对方公布的一致)
gpg --fingerprint zhangsan@example.com
验签操作(分场景):
场景 1:验证明文签名文件
# 验证file.txt.asc(明文签名文件)
gpg --verify file.txt.asc
场景 2:验证分离签名 + 原始文件
# 验证二进制分离签名(file.bin + file.bin.sig)
gpg --verify file.bin.sig file.bin
# 验证ASCII分离签名(file.bin + file.bin.asc)
gpg --verify file.bin.asc file.bin
验签成功 / 失败的输出示例:
成功(核心:Good signature from):
gpg: Signature made Thu 02 Feb 2026 10:00:00 CST
gpg: using ED25519 key D88E0F8A377388376A2A86E3F94780449446867F
gpg: Good signature from "Zhang San <zhangsan@example.com>" [ultimate]
失败(核心:BAD signature):
gpg: Signature made Thu 02 Feb 2026 10:00:00 CST
gpg: using ED25519 key D88E0F8A377388376A2A86E3F94780449446867F
gpg: BAD signature from "Zhang San <zhangsan@example.com>" [ultimate]
2、密钥生命周期管理
1)备份密钥(重中之重,避免丢失)
备份存储:私钥备份文件需存放在离线设备(U 盘 / 硬盘),公钥可上传到密钥服务器 / 官网。
点击查看代码
# 导出私钥(包含主密钥+子密钥,加密保护,需输入密码)
gpg --export-secret-keys --armor zhangsan@example.com > private_key_backup.asc
# 导出公钥(可公开)
gpg --export --armor zhangsan@example.com > public_key.asc
2)吊销密钥(子密钥泄露时紧急处理)
若子密钥泄露,可吊销子密钥并生成新的,主密钥仍可用:
点击查看代码
# 生成吊销证书(需主密钥,离线操作)
gpg --gen-revoke zhangsan@example.com > revoke_cert.asc
# 导入吊销证书并发布(吊销子密钥)
gpg --import revoke_cert.asc
gpg --send-keys D88E0F8A377388376A2A86E3F94780449446867F # 发布到密钥服务器
3)更换子密钥(定期轮换,降低风险)
点击查看代码
# 编辑密钥(进入交互模式)
gpg --edit-key zhangsan@example.com
# 在交互模式中执行:
gpg> addkey # 添加新的签名子密钥
gpg> trust # 设置信任级别
gpg> save # 保存修改
4)删除本地密钥(不再使用时)
点击查看代码
# 删除公钥
gpg --delete-keys zhangsan@example.com
# 删除私钥(需确认)
gpg --delete-secret-keys zhangsan@example.com
3、GPG 签名的典型应用场景(贴合开发 / 运维)
1)Git 提交签名(证明代码提交者身份)
配置 Git 使用 GPG 签名,确保提交记录不可伪造:
点击查看代码
# 配置Git使用GPG
git config --global user.signingkey D88E0F8A377388376A2A86E3F94780449446867F # 密钥指纹
git config --global commit.gpgsign true # 自动签名所有提交
# 提交代码(自动签名)
git commit -m "feat: add GPG signature"
# 验证提交签名
git log --show-signature
2)验证下载的软件 / 镜像(防篡改)
点击查看代码
# 下载ISO和签名文件
wget https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso
wget https://releases.ubuntu.com/24.04/SHA256SUMS.gpg
# 验证签名
gpg --verify SHA256SUMS.gpg SHA256SUMS
# 验证哈希(确保ISO未被篡改)
sha256sum -c SHA256SUMS 2>&1 | grep OK
3)邮件加密签名(防篡改 + 保密)
搭配 Thunderbird/Outlook 等邮件客户端,对邮件做 “签名 + 加密”:
签名:证明邮件是你发送的,未被篡改;
加密:只有收件人能解密邮件内容。
二、SSH
是什么?
SSH(Secure Shell,安全外壳协议)是一种加密的网络通信协议,核心目的是替代传统的 Telnet、FTP、rlogin 等明文传输协议,为远程登录、服务器管理、数据传输提供 “端到端加密” 的安全通道。
✅ 加密性:所有传输的数据(密码、指令、文件)都经过强加密,即使被监听也无法破解;
✅ 认证性:严格验证服务器和客户端的身份,防止 “中间人攻击”(伪装服务器窃取信息);
✅ 完整性:确保传输的数据不被篡改,接收方能验证数据的原始性。
怎么用?
1、SSH 的主流实现:OpenSSH
SSH 是 “协议标准”,而我们日常使用的 SSH 工具(Linux/macOS 内置、Git Bash)都是OpenSSH—— 这是 SSH 协议的开源免费实现,由 OpenBSD 团队维护,也是目前唯一的主流实现(无商业闭源版)。
2、SSH 的核心组件:客户端 + 服务端 + 密钥体系
SSH 的工作依赖 “客户端 - 服务端” 架构,加上密钥体系完成认证,三者缺一不可
(1)SSH 客户端(你操作的一端)
定义:发起 SSH 连接的工具,运行在你的本地电脑 / 设备上;
常见客户端:
- Linux/macOS:内置ssh/scp/sftp命令(OpenSSH 客户端);
- Windows:Git Bash、PuTTY、Windows Terminal(内置 OpenSSH)、Xshell;
特殊场景:Git(底层调用 OpenSSH 客户端,实现 GitLab SSH 连接)。
(2)SSH 服务端(被连接的一端)
定义:接收 SSH 连接的程序,运行在远程服务器 / GitLab 服务器上;
核心程序:sshd(Linux),默认监听 22 端口,需提前安装并启动;
核心配置:/etc/ssh/sshd_config(Linux),控制端口、认证方式、用户权限等。
(3) SSH 的密钥体系(认证的核心)
SSH 的认证依赖两类密钥:
- 客户端密钥对 客户端身份认证(如 GitLab 的 SSH key) 客户端:~/.ssh/ 私钥设密码、权限 600,绝不泄露
- 服务端主机密钥 验证服务器身份(防中间人攻击) 服务端:/etc/ssh/ 自动生成,客户端缓存到known_hosts
3、SSH完整工作流程
SSH 的核心是 “先建立安全通道,再认证身份,最后加密传输数据”,完整流程分 4 个阶段,每一步都保证安全:
阶段 1:TCP 基础连接(握手前的准备)
客户端向服务端的 22 端口(默认)发起 TCP 连接请求;服务端接受连接,建立基础的 TCP 通道(此时数据仍未加密)。
阶段 2:SSH 协议握手(协商 “加密规则”+ 验证服务器身份)
这是 SSH 安全的核心第一步,双方协商 “怎么加密”,并验证服务器是 “真的”:
- 版本协商:仅支持 SSH-2.0(SSH-1.0 有安全漏洞,已淘汰);
- 加密套件协商:双方选 “最优且兼容” 的算法组合,比如:
- 对称加密(数据传输):AES-256-GCM(高效、安全);
- 非对称加密(密钥交换):X25519(爱德华曲线,替代 RSA);
- 哈希算法(完整性校验):SHA-256;
- 主机公钥验证:客户端第一次连接服务器时,会提示 “是否信任该主机”,确认后将主机公钥缓存到~/.ssh/known_hosts—— 后续连接时,若服务器主机公钥变化(比如被中间人伪造),SSH 会直接拒绝连接,这是防中间人攻击的核心;
- 会话密钥:握手阶段生成的临时对称密钥,仅用于本次 SSH 会话的 Data 传输,会话结束即失效,避免长期密钥泄露风险。
阶段 3:身份认证(验证 “你是你”,核心是 SSH key)
握手完成后,服务端需要验证客户端的身份,SSH 支持多种认证方式,这里只推荐公钥认证方式:
公钥认证(推荐,GitLab / 服务器首选)
- 客户端向服务端发送 “自己的公钥指纹 + 请求用公钥认证”;
- 服务端检查:该公钥是否在~/.ssh/authorized_keys(服务器端,对应用户的授权列表)中;
- 若存在,服务端用该公钥加密一个 “随机字符串”,发给客户端;
- 客户端用本地私钥解密该字符串,返回给服务端;
- 服务端验证解密结果:正确则认证通过,错误则拒绝。
阶段 4:加密数据传输(认证后的正常操作)
- 身份认证通过后,客户端和服务端就进入 “加密数据传输阶段”:
- 所有数据(指令、文件、Git 操作)都用 “会话密钥”(对称加密)加密后传输;
- 每段数据都附加哈希值,接收方验证哈希,确保数据未被篡改;
- 会话结束(断开 SSH),会话密钥立即失效,下次连接重新生成。
4、SSH key
是什么?
SSH key(SSH 密钥对)是基于 SSH(Secure Shell)协议的非对称加密身份认证机制,也是目前远程服务器 / 代码仓库最主流的安全认证方式。SSH key 是由「公钥(Public Key)+ 私钥(Private Key)」组成的密钥对,基于非对称加密算法生成(推荐 Ed25519,次之 RSA)。
在SSH场景里的认证核心:“你拥有私钥” = “你是合法身份”,服务器只需验证你能解密公钥加密的内容,即可确认身份,无需传输密码。
怎么用?
1)SSH key 的核心组成(两个文件,缺一不可)
生成 SSH key 后,本地会生成两个文件(默认路径:~/.ssh/,Windows 为C:\Users\你的用户名.ssh\):ed25519算法:
- id_ed25519:私钥,本地保存,用于解密服务器的认证信息,极高:设置密码、文件权限 600、绝不泄露;
- id_ed25519.pub:公钥,上传到 GitLab / 服务器,用于加密认证信息 无:可公开,泄露无风险
注:若用 RSA 算法(必须使用 4096 位(2048 位已不安全)),文件名为id_rsa/id_rsa.pub;优先选 Ed25519(更安全、效率更高)。
2)GitLab 配置 SSH key 的完整步骤
步骤 1:生成 Ed25519 SSH 密钥对
点击查看代码
# 生成Ed25519密钥对,-C是备注(建议填GitLab绑定的邮箱,便于识别)
ssh-keygen -t ed25519 -C "your_email@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/yourname/.ssh/id_ed25519): # 直接回车,用默认路径
Enter passphrase (empty for no passphrase): # 建议设置私钥密码(防止私钥文件泄露后被滥用)
Enter same passphrase again: # 重复密码
生成成功后,~/.ssh/目录下会出现id_ed25519(私钥)和id_ed25519.pub(公钥)。
步骤 2:查看并复制公钥
点击查看代码
# 查看公钥内容(Linux/macOS)
cat ~/.ssh/id_ed25519.pub
# Windows(Git Bash)
cat /c/Users/你的用户名/.ssh/id_ed25519.pub
步骤 3:上传公钥到 GitLab
- 登录 GitLab,点击右上角头像 →「Settings」→「SSH Keys」;
- 在「Key」输入框粘贴复制的公钥内容;
- (可选)在「Title」输入密钥名称(如 “我的办公电脑”),便于识别;
- 点击「Add key」,完成公钥绑定。
步骤 4:测试 SSH 连接(验证配置是否成功)
点击查看代码
# 测试与GitLab的SSH连接
ssh -T git@gitlab.com

浙公网安备 33010602011771号