简短回答:运行 ssh-keygen -t ed25519 -C "you@host-year",并为密钥设置密码短语;自 OpenSSH 9.5 起,Ed25519 一直是默认类型。如果你有 FIDO2 安全密钥,优先使用 -t ed25519-sk(认证器不支持 Ed25519 时用 -t ecdsa-sk),这样私钥永远不会存放在磁盘上。RSA 只用于别无选择的系统,而且密钥长度要达到 3072 位或以上:自2026年10月14日起,GitHub 拒绝添加更短的新 RSA 密钥。把密钥加载到 SSH 代理时设置有效期(ssh-add -t 8h),不要把代理转发到不受你控制的主机上(改用 ProxyJump),并用 ssh-add -h 把密钥限定在指定的目标主机上。管理大量服务器时,用短期 SSH 证书取代分散各处的 authorized_keys 条目。会话的后量子保护已经开启:OpenSSH 10 默认协商 mlkem768x25519-sha256,服务器不支持时会发出警告。新的混合签名类型 ssh-mldsa44-ed25519(OpenSSH 10.6)值得测试,但还不值得作为你唯一的密钥来部署。
这些命令于2026年10月20日在 debian:forky-20261005-slim 中运行,使用的是 Debian 软件包 openssh-client 和 openssh-server 1:10.6p1-1。所有密钥都是为本文生成的。
选择哪种密钥类型
-t | 是什么 | 适用场景 |
|---|---|---|
ed25519(默认) | Ed25519,32 字节公钥,确定性签名 | 几乎所有情况 |
ed25519-sk、ecdsa-sk | FIDO2 密钥:私钥始终留在认证器中,每次签名都需要触摸一下 | 你有安全密钥,且服务器运行 OpenSSH 8.2 或更高版本 |
ecdsa | 基于 P-256、P-384 或 P-521 的 ECDSA | 策略要求使用 NIST 曲线 |
rsa | RSA,自 OpenSSH 8.0 起默认 3072 位 | 旧服务器、专用设备、部分 HSM |
mldsa44-ed25519 | ML-DSA-44 + Ed25519 混合签名,10.6 新增 | 测试后量子身份验证 |
DSA 已经不复存在:OpenSSH 10.0(2025年4月)移除了它,“完成了始于2015年的弃用过程”。RSA 密钥本身没有问题;OpenSSH 8.8(2021年9月)禁用的是用 SHA-1 计算哈希的 ssh-rsa 签名算法。同一个 RSA 密钥可以用 rsa-sha2-256 或 rsa-sha2-512 签名,因此关于 ssh-rsa 的服务器报错通常靠升级客户端就能解决,而不必更换密钥。GitHub 也遵循同样的思路:在2026年11月4日和12月9日两次临时停用(brownout)之后,它将于2027年1月13日移除 ssh-rsa 签名;自2026年10月14日起,它只接受 3072 位及以上的新 RSA 密钥。
ssh-keygen 10.6 生成的文件大小(.pub 行包含注释):
ssh-keygen -q -t rsa -N '' -f ~/rsa_default
ssh-keygen -q -t ecdsa -N '' -f ~/ecdsa_default
ssh-keygen -q -t mldsa44-ed25519 -N '' -f ~/.ssh/id_mldsa44_ed25519
for f in ~/rsa_default ~/ecdsa_default ~/.ssh/id_ed25519 ~/.ssh/id_mldsa44_ed25519; do
ssh-keygen -l -f "$f.pub"
printf ' public key line: %s bytes, private key file: %s bytes\n' "$(wc -c < "$f.pub")" "$(wc -c < "$f")"
done
3072 SHA256:NGv36ZHCwauN4GGrdKSDZPnKTn6nFuLSVRS01/eSXOs alice@59151e7fff6c (RSA)
public key line: 572 bytes, private key file: 2602 bytes
256 SHA256:4ODqYFVTGSwjx7pfis5ZtZ02PKaSd15alII7RIHPhE8 alice@59151e7fff6c (ECDSA)
public key line: 180 bytes, private key file: 513 bytes
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)
public key line: 99 bytes, private key file: 464 bytes
512 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 alice@59151e7fff6c (MLDSA44-ED25519)
public key line: 1868 bytes, private key file: 3982 bytes
混合密钥的公钥行是 Ed25519 公钥行的 19 倍。这会影响 authorized_keys 文件、证书,以及所有把密钥存进按 Ed25519 长度设计的数据库字段的系统。对比文章 Ed25519 与 RSA 详细介绍了这对经典算法。
生成密钥
ssh-keygen -t ed25519 -C "alice@laptop-2026" -N 'correct horse battery staple' -f ~/.ssh/id_ed25519
Created directory '/home/alice/.ssh'.
Generating public/private ed25519 key pair.
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026
The key's randomart image is:
+--[ED25519 256]--+
| ..o*..... |
| o . .=... =. |
|. o .. +. + o. |
| . . . o =. . ...|
| o + S .. ..|
| . . o + B |
| . * = * o . |
| o E = o.+ |
| o oo. . |
+----[SHA256]-----+
这里用 -N 在命令行中传入密码短语,只是因为实验是用脚本运行的;交互使用时应省略它,让 ssh-keygen 提示你输入,这样密码短语就不会留在 shell 历史记录中。注释是保存在公钥中的自由文本:写上姓名、机器和年份,多年后仍能审计 authorized_keys。服务器日志记录的是指纹(SHA256:…),因此无论在哪里注册密钥,都要把它记下来。
密码短语与 KDF 轮数
没有密码短语时,私钥文件就是密钥本身:被盗的备份、笔记本电脑的磁盘镜像或配置错误的同步文件夹都会把它拱手交出。有了密码短语,文件会用 bcrypt_pbkdf 派生出的密钥加密。OpenSSH 私钥格式把加密算法、KDF 及其轮数记录在文件头中,任何人不需要密码短语就能读取:
"""Print the cipher, KDF and bcrypt rounds from the header of an OpenSSH private key file (openssh-key-v1)."""
import base64
import struct
import sys
text = open(sys.argv[1]).read()
body = "".join(line for line in text.splitlines() if not line.startswith("-----"))
blob = base64.b64decode(body)
magic = b"openssh-key-v1\0"
assert blob.startswith(magic), "not an OpenSSH private key"
pos = len(magic)
def string():
global pos
(length,) = struct.unpack(">I", blob[pos : pos + 4])
value = blob[pos + 4 : pos + 4 + length]
pos += 4 + length
return value
cipher = string().decode()
kdf = string().decode()
options = string()
line = f"cipher={cipher} kdf={kdf}"
if kdf == "bcrypt":
(salt_len,) = struct.unpack(">I", options[:4])
(rounds,) = struct.unpack(">I", options[4 + salt_len : 8 + salt_len])
line += f" salt={salt_len} bytes rounds={rounds}"
print(line)
python3 kdfinfo.py ~/.ssh/id_ed25519
for r in 32 100 500; do
ssh-keygen -q -p -a $r -P 'correct horse battery staple' -N 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null
s=$(date +%s.%N); ssh-keygen -y -P 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null; e=$(date +%s.%N)
printf 'rounds=%s unlock=%.2fs\n' $r $(echo "$e - $s" | bc)
done
cipher=aes256-ctr kdf=bcrypt salt=16 bytes rounds=32
rounds=32 unlock=0.16s
rounds=100 unlock=0.52s
rounds=500 unlock=2.59s
默认轮数在 OpenSSH 9.4 之前是 16,从 9.4 起是 24,自 10.6 起是 32。正如 10.6 的版本说明所指出的,耗时与轮数呈线性关系(“不像 bcrypt(3) 那样呈指数增长”),因此上面的数字可以按比例推算:选择你能接受其解锁延迟的最大值,因为复制了文件的攻击者每猜一次也要付出同样的代价。ssh-keygen -p -a 100 -f ~/.ssh/id_ed25519 会重新加密已有的密钥;每个会话只把密钥加载到代理中一次,就只需承受一次延迟。自 10.6 起,OpenSSH 会拒绝轮数超过一百万的密钥,因此恶意构造的密钥文件无法拖住解析它的服务。
密码短语保护的是静态存储的文件。如果机器已被入侵,而密钥已经在代理中解密,密码短语就起不了任何作用——这正是硬件密钥的用武之地。
硬件支持的密钥:-sk
ed25519-sk 和 ecdsa-sk 密钥(OpenSSH 8.2 及更高版本)把私钥保存在 FIDO2 认证器中,例如 YubiKey 或平台认证器。此时文件 ~/.ssh/id_ed25519_sk 只保存一个密钥句柄,认证器需要用它来重建密钥;离开设备,这个文件毫无用处。每次签名都需要用户在场(触摸一下),使用 -O verify-required 时还需要输入 PIN。以下是关键选项,说明引自 ssh-keygen(1):
-O resident把密钥句柄存储在认证器上,这样在另一台计算机上也能用ssh-keygen -K或ssh-add -K加载它。手册警告说,这会“增加攻击者利用被盗认证器设备的可能性”,因此要同时设置 PIN。-O verify-required要求每次签名都进行用户验证(目前是 PIN);服务器可以通过authorized_keys中的verify-required选项强制要求这一点。-O application=ssh:work用于在同一设备上区分多个驻留密钥;该字符串必须以ssh:开头。-O no-touch-required取消触摸要求,而除非authorized_keys明确允许,否则 sshd 会拒绝这类签名。-O write-attestation=path保存认证器的证明,组织可以借此在注册时证实密钥是在经过批准的硬件上生成的。
ssh-keygen -t ed25519-sk -O resident -O verify-required -O application=ssh:work -C "alice@yubikey-2026"
这条命令我们没有运行:容器中没有认证器,没有认证器时的运行记录只会显示错误。一些较旧的认证器只实现了 P-256,对它们要用 ecdsa-sk。平台密钥也可以使用,但由笔记本电脑安全硬件保存的密钥有其自身的利弊,详见硬件支持的密钥。
后量子:密钥交换先行,签名随后
SSH 的这两部分面临不同的期限。会话密钥来自密钥交换;如果密钥交换日后被攻破,被录下的流量就能被解密(“先收集后解密”攻击)。主机签名和用户签名只在建立连接的那一刻起作用:未来的量子计算机无法回到过去,伪造一次已经发生的登录。因此 OpenSSH 先切换了密钥交换:
sntrup761x25519-sha512自 OpenSSH 9.0(2022年)起默认启用。mlkem768x25519-sha256(ML-KEM-768 与 X25519 的组合)自 OpenSSH 10.0(2025年4月)起成为默认,现已由 RFC 10042(信息类,2026年)规范。- 自 10.1 起,会话回退到经典密钥交换时客户端会输出警告;自 10.6 起,服务器也会把这种情况记入日志。
debug1: kex: algorithm: mlkem768x25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: Server host key: ssh-ed25519 SHA256:Qw4tNHnCo8UwS2qNXROrEm8RP+d+ccaVbwAzv8lLX+I
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
debug1: Server accepts key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
Authenticated to localhost ([::1]:22) using "publickey".
连接一台限定为 KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256 的服务器时,默认配置的客户端输出了:
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html
我们还观察到两个细节:如果是你自己把 KexAlgorithms 限定为经典方法,客户端不会发出警告(这条警告针对的是服务器);而服务器会记录每一个这样的会话,例如 connection from ::1 port 38814 is not using a post-quantum key exchange algorithm: "curve25519-sha256" [preauth]。对于你无法修复的主机,可以按照 openssh.com/pq.html 的建议,在 Match host 块中写入 WarnWeakCrypto no-pq-kex,让客户端不再警告。GitHub 宣布自2026年10月14日起为 github.com 启用 mlkem768x25519-sha256;10月20日,我们的 10.6 客户端与 git@github.com 协商出了这一算法。
签名是第二步。OpenSSH 10.4 加入了实验性的 ML-DSA-44 + Ed25519 复合签名;10.6 以 ssh-mldsa44-ed25519 的名称启用了它,其规范是 SSHM 工作组草案 draft-ietf-sshm-composite-sigs。用 10.4 实验代码生成的密钥必须重新生成。在 Debian 的 10.6 软件包中,ssh-keygen -A 在 RSA、ECDSA 和 Ed25519 主机密钥旁边生成了 ssh_host_mldsa44_ed25519_key,而该类型位于默认 HostKeyAlgorithms 列表的末尾,因此客户端仍会选择 Ed25519。显式指定这一类型,整个流程都能正常工作:
debug1: kex: host key algorithm: ssh-mldsa44-ed25519
debug1: Server host key: ssh-mldsa44-ed25519 SHA256:UVOUu+csMH8i8Zd/oWzokAGfzRYFetOncVzB4vYeMgQ
debug1: Server accepts key: /home/alice/.ssh/id_mldsa44_ed25519 MLDSA44-ED25519 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 explicit
Authenticated to localhost ([::1]:22) using "publickey".
两个组成部分对同一条经过域分离的消息签名,而且“任一验证操作失败都必须(MUST)导致复合签名验证失败”,因此这种混合签名目前不比 Ed25519 弱。它的代价在于体积(据草案,每次身份验证需要一个 2,484 字节的签名)和兼容性:不认识这种类型的服务器、代码托管平台、跳板机和库都不会接受这个密钥。生成一个这样的密钥,在你自己运行的主机上测试,同时保留已注册的 Ed25519 密钥。
代理与代理转发
ssh-agent 持有已解密的密钥,并按请求签名;程序通过 SSH_AUTH_SOCK 中的套接字访问它。自 OpenSSH 10.1 起,这个套接字位于 ~/.ssh/agent 下,而不是 /tmp。添加密钥时设置有效期,这样被遗忘的会话就不会让密钥永远处于解锁状态:
eval "$(ssh-agent -s)" >/dev/null
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
ssh-add -t 8h ~/.ssh/id_ed25519
ssh-add -l
SSH_AUTH_SOCK=/home/alice/.ssh/agent/s.eaeHp0xOjD.local.660.o5M944i4eW
Identity added: /home/alice/.ssh/id_ed25519 (alice@laptop-2026)
Lifetime set to 08:00:00
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)
~/.ssh/config 中的 AddKeysToAgent 会在首次使用密钥时完成同样的操作,并且可以指定有效期(AddKeysToAgent 8h)或 confirm;后者与 ssh-add -c 一样,会在每次签名前请求确认。
代理转发(ssh -A、ForwardAgent yes)会把这个套接字暴露在远程主机上。ssh_config(5) 直截了当地说明了风险:“攻击者无法从代理中获取密钥材料,但可以使用这些密钥执行操作”。只要你保持连接,远程主机上任何拥有 root 权限的人都能以你的身份登录任何接受你密钥的地方。更好的做法有两个:
- 跳转,而不是转发:
ssh -J bastion target(或在配置中写ProxyJump bastion)从你自己的机器发起第二个连接,经由转发的 TCP 流到达目标;跳板机永远接触不到你的代理。 - 限制密钥:
ssh-add -h(OpenSSH 8.9 及更高版本)把密钥绑定到由known_hosts中的主机密钥标识的目标主机上;在确实需要转发时,还可以绑定到各个跳转环节(bastion>target)。
ssh-add -h prod-host ~/agent_only_key
ssh -o BatchMode=yes prod-host 'echo signed in on prod-host'
ssh -v -o BatchMode=yes build-host true 2>&1 | grep -iE 'agent|Offering|Permission denied|Authenticated|identity'
Identity added: /home/alice/agent_only_key (alice@laptop)
signed in on prod-host
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:MA2nEhBnMlCkX3pWWgPtff90dRZF9D9k8i2svCUK1II
alice@127.0.0.2: Permission denied (publickey,password).
代理把会话绑定到 build-host 的主机密钥,随后没有为它列出任何身份:密钥是存在的,只是不能用于这个目标主机。手册对这种限制的边界说得很谨慎:约束“并不能阻止能够访问远程 SSH_AUTH_SOCK 的攻击者再次转发它,并在另一台主机上使用它(但只能用于允许的目标)”。
用证书取代 authorized_keys
把公钥复制到每台服务器的 authorized_keys 中,这种做法无法扩展,还会让吊销变成一个查找难题。SSH 证书是由 CA 密钥签名的公钥,附带身份、主体(principal)、序列号和有效期。服务器只需信任 CA 一次(TrustedUserCAKeys),并检查吊销列表(RevokedKeys):
ssh-keygen -s /etc/ssh/user_ca -I "alice@example.com 2026-10-20" -n alice -V +8h -z 1042 /home/alice/.ssh/id_cert_user.pub
ssh-keygen -L -f /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -i ~/.ssh/id_cert_user localhost "echo logged in with certificate"'
echo "serial: 1042" > /tmp/revoke.txt
ssh-keygen -k -u -s /etc/ssh/user_ca.pub -f /etc/ssh/revoked.krl /tmp/revoke.txt
ssh-keygen -Q -f /etc/ssh/revoked.krl /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -o BatchMode=yes -i ~/.ssh/id_cert_user localhost true'
Signed user key /home/alice/.ssh/id_cert_user-cert.pub: id "alice@example.com 2026-10-20" serial 1042 for alice valid from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
/home/alice/.ssh/id_cert_user-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Public key: ED25519-CERT SHA256:eVstR5lK6VBztjl2AYyWcv8C6xwNahEEVSrQpe7Y/LE
Signing CA: ED25519 SHA256:+URM6AMiGUu+gv/gxoQgpOhHP4CUN1fznXWDlVxorbY (using ssh-ed25519)
Key ID: "alice@example.com 2026-10-20"
Serial: 1042
Valid: from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
Principals:
alice
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc
logged in with certificate
Revoking from /tmp/revoke.txt
/home/alice/.ssh/id_cert_user-cert.pub (alice@ci-runner): REVOKED
alice@localhost: Permission denied (publickey).
sshd 记录了 key ED25519-CERT SHA256:eVst… revoked by file /etc/ssh/revoked.krl。注意默认扩展:除非签名时使用 -O clear,并且只加回需要的扩展(-O permit-pty),否则证书会允许代理转发和端口转发。把 CA 密钥离线保存或放在 HSM 中,证书有效期以小时而不是以年计,短有效期能让大多数吊销变得没有必要。主机证书(签名时加 -h,在 known_hosts 中写 @cert-authority)以同样的方式消除了首次使用即信任时的确认提示。
轮换密钥
- 用户密钥:生成新密钥,在所有地方(服务器、代码托管平台、CI 机密)把新公钥添加到旧公钥旁边,用
-i new_key -o IdentitiesOnly=yes连接以确认它可用,然后删除旧的那一行。带日期的注释能告诉你哪一行是旧的。 - 主机密钥:自 OpenSSH 8.5 起,
UpdateHostKeys默认开启(除非你覆盖了UserKnownHostsFile或启用了VerifyHostKeyDNS):身份验证完成后,服务器会公布它的所有主机密钥,客户端则记录其中新的密钥,因此服务器可以在停用旧密钥之前先发布替代密钥。很少连接的客户端会错过这个时间窗口;主机证书可以避免这个问题。 - 算法:同一机制也能完成算法迁移——添加 Ed25519 主机密钥(以后再添加混合主机密钥),让客户端记住它,然后移除 RSA 密钥。
- 盘点:
ssh-keygen -l -f authorized_keys为每一行输出一个指纹;把它们与 sshd 日志中的Accepted publickey … SHA256:行对照,就能找出没有人使用的密钥。
常见错误
- 所有人可读的密钥文件:
ssh拒绝使用它,并输出 WARNING: UNPROTECTED PRIVATE KEY FILE!。用chmod 600设置密钥文件的权限,.ssh目录则设为700。 - 密码短语错误或密钥经过转换:incorrect passphrase supplied to decrypt private key 和 error in libcrypto 看起来相似;后者通常意味着文件已损坏,或者其格式是当前构建无法读取的。库需要显式传入密码短语,Go 的 this private key is passphrase protected 就说明了这一点。
- 代理中的密钥太多:sshd 在
MaxAuthTries(6)次尝试失败后就会放弃,报出Too many authentication failures并断开连接,而客户端尝试的每个密钥都可能消耗一次机会(OpenSSH 10.6 的服务器额外允许 6 次“是否接受这个密钥”的查询,即PubkeyOptions max-pk-ok)。为每台主机设置IdentityFile和IdentitiesOnly yes。如果提供的密钥都没有注册,就会得到 Permission denied (publickey)。 - 代理拒绝签名:agent refused operation 表示服务器接受了密钥,但代理不肯签名:可能是没有及时触摸 FIDO 密钥、代理无法显示确认提示、令牌已锁定,或者磁盘上的密钥文件与代理持有的密钥已不再一致。
- 过旧的对端:no matching host key type found. Their offer: ssh-rsa 表示服务器只能用 SHA-1 签名。应升级服务器;针对单台主机的
HostKeyAlgorithms +ssh-rsa只能是临时例外,绝不能作为全局设置。 - 忽略已变更的主机密钥:REMOTE HOST IDENTIFICATION HAS CHANGED 要么是可以通过带外渠道确认的计划内轮换,要么恰恰是这项检查要防范的攻击。只有在弄清是哪一种之后,才能用
ssh-keygen -R host删除旧的那一行。
检查清单
ssh-keygen -t ed25519(有安全密钥时用-t ed25519-sk),设置密码短语,注释中写明所有者、机器和年份。- 把 KDF 轮数提高到你能接受的延迟(在这里
-a 100大约需要半秒)。 - 每台设备一个密钥;切勿在机器之间复制私钥。
- 代理中的密钥设置有效期;为每台主机设置
IdentitiesOnly yes;用ProxyJump代替ForwardAgent;不得不转发时使用ssh-add -h。 - 服务器集群:使用短有效期的用户证书和主机证书,CA 密钥离线保存,每台服务器上部署 KRL。
- 在
ssh -v的输出中查找kex: algorithm: mlkem768x25519-sha256;把后量子警告当作一张升级服务器的工单来处理。 - 用你自己的服务器测试
mldsa44-ed25519密钥;在所有对端都接受混合签名之前,保留一个已注册的经典密钥。
来源
- OpenSSH 版本说明:8.5(UpdateHostKeys 默认开启)、8.8(禁用 RSA/SHA-1)、8.9(目标约束)、9.0(sntrup761x25519)、9.4 和 10.6(KDF 轮数)、9.5(Ed25519 成为默认)、10.0(ML-KEM 成为默认,移除 DSA)、10.1(警告、代理套接字)、10.4 和 10.6(ML-DSA-44 + Ed25519)
- OpenSSH:后量子密码
- 手册页:ssh-keygen(1)、ssh-add(1)、ssh_config(5)
- RFC 10042:SSH 中基于 ML-KEM 的 PQ/T 混合密钥交换
- draft-ietf-sshm-composite-sigs:SSH 中的后量子复合签名
- GitHub 更新日志:SSH 安全改进(2026年9月22日)