首页 / 资讯中心 / 文章详情

SSH密钥格式转换指南:PEM、PKCS#8、OpenSSH与PPK互转

SSH密钥格式转换指南:PEM、PKCS#8、OpenSSH与PPK互转 ★ FEATURED ARTICLE
手上攒了七八种 SSH 密钥文件结果换台机器一个都导不进去——这种事我见过太多次了。有人从云控制台下载下来的是-----BEGIN RSA PRIVATE KEY-----开头的老式 PEM有人用ssh-keygen现生成的是-----BEGIN OPENSSH PRIVATE KEY-----还有人从 PuTTY 那边导出的是.ppk更别提 Java 那边 JSch 死活报invalid privatekey。SSH 公钥私钥格式转换这件事说白了就是一句话密钥材料本身没变变的只是外面套的那层壳。你要做的是把壳换掉而不是重新造一把钥匙。我这次把手上踩过的坑、常用的命令、以及各类工具之间的能力边界整理一遍覆盖 RSA、ECDSA、Ed25519 三种主流算法涉及纯 PEM、PKCS#8、OpenSSH 新格式、RFC4716、PuTTY PPK 这几种封装。读者如果是刚接触 Linux 运维、准备用 Java 或 Python 代码对接 SFTP、要在 Windows 上用 WinSCP 连服务器或者要给一批机器做免密登录这篇内容基本能当手册用。命令都是我在 OpenSSH 8.x/9.x、OpenSSL 3.x、PuTTY 0.78 这一代工具上实测过的版本差异我会单独标出来。1. SSH 密钥的外壳到底有多少种1.1 私钥的几种常见封装拿head -1看一眼文件首行基本就能判断手里这把钥匙属于哪一类。我按实际遇到频率从高到低排一下格式首行标识常见来源兼容面PKCS#1传统 PEM-----BEGIN RSA PRIVATE KEY-----ssh-keygen -m PEM、openssl genrsa极广老 Java/JSch 只认它PKCS#8 未加密-----BEGIN PRIVATE KEY-----openssl pkcs8 -topk8 -nocryptJavaBouncyCastle、Go、.NETPKCS#8 加密-----BEGIN ENCRYPTED PRIVATE KEY-----openssl pkcs8 -topk8同上但调用方必须传密码OpenSSH 新格式-----BEGIN OPENSSH PRIVATE KEY-----ssh-keygen默认7.8 之后OpenSSH 6.5、新版 ParamikoSEC1EC 专用-----BEGIN EC PRIVATE KEY-----openssl ecparam -genkey多数库能读需转 PKCS#8 兼容老代码PuTTY PPKPuTTY-User-Key-File-2或-3puttygenPuTTY、WinSCP、TortoiseGitSSH2Tectia 系---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----老商业 SSH 客户端非常窄一般需要重新生成前五种都是文本 PEM 家族的肉眼能直接打开PPK 也是文本但结构完全不同是一段自定义字段加 base64。最后一种 SSH2 私钥属于历史遗留ssh-keygen根本没有写出它的能力遇到只能重新生成。有一点要建立直觉PKCS#1 和 PKCS#8 是容器规范OpenSSH 新格式是 OpenSSH 自己定的私有容器PPK 是 PuTTY 自己定的容器。它们之间的差别相当于同一个 8 位密码装在木盒里、铁盒里还是带指纹锁的保险柜里里面那把钥匙模数 n、指数 e、私钥 d是不变的。1.2 公钥的三种写法公钥就简单多了只有三种常见写法而且互相转换非常干净OpenSSH 单行格式ssh-rsa AAAAB3NzaC1yc2E... userhost~/.ssh/id_rsa.pub就是这么存的占一行前面是算法名中间是 base64最后是注释。RFC4716也叫 SSH2 公钥长这样算法名在头部正文 base64 折行---- BEGIN SSH2 PUBLIC KEY ---- Comment: 2048-bit RSA, converted by userhost AAAAB3NzaC1yc2EAAAADAQABAAABAQD... ---- END SSH2 PUBLIC KEY ----PEM / SPKI 格式-----BEGIN PUBLIC KEY-----开头本质是 X.509 SubjectPublicKeyInfo跟 TLS 证书里那段公钥是同一种东西。云平台控制台让你粘贴的公钥、K8s Secret 里塞的、Java 校验签名用的多半要这个。三种写法里OpenSSH 单行是事实标准其他两种都是特定软件的要求。转换时我常用ssh-keygen -eexport和ssh-keygen -iimport这一对参数下面第 4 节会展开。1.3 为什么会有这么多格式不搞清楚历史很容易把格式转换当成玄学。实际原因很实在。早期 OpenSSH 复用了 OpenSSL 的 PEM 读写代码所以私钥天然是 PEM。但 PEM 的老式加密有硬伤kdf 是用 MD5 做一次简单迭代参数固定且只支持 RSA 和 DSA加解密细节还带点实现自由发挥。于是 OpenSSH 在 6.5 版本引入了openssh-key-v1这个自定义容器支持 bcrypt 派生还能把 Ed25519、ECDSA 一起装进去7.8 版本之后直接设为默认。PuTTY 走 Windows 路线自带 PPK。PPK v2 用 SHA-1 派生v3 开始换 Argon2id抗暴力破解强了很多但代价是老版本 WinSCP、TortoiseGit 读不了 v3这就是为什么你从新 PuTTY 导出的 ppk 在老工具里会提示无法加载。Java 生态则是另一条线。JSch 这个库从 2018 年起基本停更一直只认 PKCS#1 和未加密 PKCS#8OpenSSH 新格式、Ed25519 全都不支持。所以你会看到从云主机下载的私钥喂给 Java 就报 invalid privatekey根子在这里。2. 转换工具怎么选ssh-keygen 打主力openssl 和 puttygen 补位2.1 ssh-keygen 的 -m 参数才是真正的转换开关很多人以为-m是生成密钥时用的其实它主要出现在两个场景。一个是-p修改密码/格式另一个是-e/-i导入导出公钥。生成新密钥时选算法用-t格式由版本默认决定。把一把 OpenSSH 新格式的 RSA 私钥转成传统 PEM完整操作用这三行cp id_rsa id_rsa.bak ssh-keygen -p -f id_rsa -m PEM -P 旧密码 -N 新密码 head -1 id_rsa几个参数必须说清楚。-p表示修改已有私钥是原地覆盖所以第一行的备份不是可选项而是必须项我吃过一次没备份的亏一把生产密钥的密码忘了直接卡住。-P是原密码-N是新密码两个都省略会进交互提示。想清掉密码就写成-N 注意单引号里的空串必须保留不然 shell 会把后面参数吃掉。-m的可选值有PEM、PKCS8、RFC4716、OPENSSH四种前两个用于私钥RFC4716和OPENSSH主要用于公钥导出导入。转换完之后做两件事验证head -1看首行变成-----BEGIN RSA PRIVATE KEY-----ssh-keygen -lf id_rsa看指纹跟转换前用ssh-keygen -lf id_rsa.pub得到的一致。指纹一致就说明材料没动只是换了壳。如果指纹变了说明你操作的对象错了或者中途生成了新密钥这时候千万别继续往下用。2.2 openssl 负责 PKCS#1 与 PKCS#8 的细粒度互转ssh-keygen智能处理 RSA 和 ECDSA但对 DER 二进制输出、加密算法的选择、EC 参数的处理都不够灵活这些交给 openssl。# 转 PKCS#8 未加密PEM openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_p8.pem # 转 PKCS#8 加密AES-256-CBC openssl pkcs8 -topk8 -in key.pem -out key_p8_enc.pem -v2 aes-256-cbc # 转回传统 PKCS#1 openssl rsa -in key.pem -out key_trad.pem -traditional # 输出二进制 DER openssl rsa -in key.pem -outform DER -out key.der openssl pkcs8 -topk8 -nocrypt -in key.pem -outform DER -out key_p8.der # EC 私钥处理 openssl pkcs8 -topk8 -nocrypt -in ec_sec1.pem -out ec_p8.pem # 从私钥导出 PEM 公钥 openssl rsa -in key.pem -pubout -out key_pub.pem这里有个真坑OpenSSL 3.0 改了openssl rsa -in -out的默认输出行为。1.1.1 时代默认输出传统 PKCS#13.0 之后默认输出 PKCS#8。同一段脚本在两台机器上跑出两种结果非常容易误判。稳妥做法是无论哪个版本都显式带上-traditional想要 PKCS#8 就直接走openssl pkcs8不要依赖默认值。2.3 puttygen 处理 PPK 是唯一靠谱方案PPK 和 PEM 之间没有官方互转公式必须先解出内部结构再重新封装puttygen是唯一稳妥的工具。Linux 上apt install putty-tools就有Windows 上直接拿 PuTTY 安装包里的puttygen.exe。# OpenSSH 私钥转 PPK puttygen id_rsa -O private -o id_rsa.ppk # PPK 转回 OpenSSH旧格式PEM 风格 puttygen id_rsa.ppk -O private-openssh -o id_rsa_pem # PPK 转 OpenSSH 新格式容器 puttygen id_rsa.ppk -O private-openssh-new -o id_rsa_new # 从 PPK 导出公钥 puttygen id_rsa.ppk -O public-openssh -o id_rsa.pub带密码的情况用文件传参避免 shell 转义问题echo 旧密码 old.txt echo 新密码 new.txt puttygen id_rsa.ppk -O private-openssh -o id_rsa_pem \ --old-passphrase old.txt --new-passphrase new.txt rm -f old.txt new.txt用完立刻删掉密码文件这是习惯问题。密码为空就写个空文件。2.4 各工具能力对照工具能读能写适合场景ssh-keygenOpenSSH、PEM、PKCS#8、RFC4716PEM、PKCS#8、OpenSSH、RFC4716日常主力改密码、换格式opensslPEM、PKCS#1、PKCS#8、DER同上需要 DER、指定加密算法、EC 处理puttygenPPK、OpenSSH、PEMPPKv2/v3、OpenSSH、SSH2Windows 生态、PPK 互转JSchJavaPKCS#1、未加密 PKCS#8不支持写代码对接 SFTP 时的读取端ParamikoPythonOpenSSH、PKCS#1、未加密 PKCS#8不支持写Python 自动化脚本读取端3. 私钥格式转换实操从 OpenSSH 新格式一路转到 PPK3.1 OpenSSH 新格式转 PEMJava 对接 SFTP 的必修课场景大概是这样的你在 Linux 上ssh-keygen -t rsa -b 4096生成了一把默认密钥用命令行登录服务器一切正常然后要把这把钥匙交给一段 Java 代码去传文件结果代码里抛com.jcraft.jsch.JSchException: invalid privatekey。问题就在首行是-----BEGIN OPENSSH PRIVATE KEY-----。转换只需一条命令建议连着备份一起cp ~/.ssh/id_rsa ~/.ssh/id_rsa.openssh.bak ssh-keygen -p -m PEM -f ~/.ssh/id_rsa -N head -1 ~/.ssh/id_rsa第四条命令期望输出-----BEGIN RSA PRIVATE KEY-----。这里-N 是顺手清掉密码因为 JSch 里传密码的写法比较绕先在测试环境确认通畅更省事。生产环境建议保留密码然后代码侧用addIdentity(privateKeyPath, passphrase)传。注意一个极易踩的坑不要把同一把密钥同时在两个地方用两种格式维护。我见过同事复制出id_rsa_pem单独给 Java 用结果后来轮换密钥时只更新了id_rsaJava 那边一直用旧的排查半天。正确做法是转换后只保留一份需要什么格式在部署时现场转或者用配置管理工具统一下发。还要提一句这一步对 Ed25519 私钥会失败。ssh-keygen -p -m PEM -f id_ed25519通常会报invalid format之类因为传统 PEM 结构里没有 Ed25519 的对应定义。遇到这种只能从应用侧解决——升级解析库或者换成 RSA 重新签发。3.2 PEM 与 PKCS#8 互转顺手处理 DERJava 那边如果用 BouncyCastle 而不是 JSch反而是 PKCS#8 更好用.NET 的RSA.ImportPkcs8PrivateKey也只吃 PKCS#8某些云厂商的 API 上传密钥时明确要求 PKCS#8。转换命令前面列过这里强调验证方法openssl pkcs8 -topk8 -nocrypt -in id_rsa -out id_rsa_p8.pem head -1 id_rsa_p8.pem # 期望 -----BEGIN PRIVATE KEY----- openssl pkey -in id_rsa_p8.pem -check -nooutopenssl pkey -check会校验密钥结构自洽性并打印RSA key ok这是我每次转完都会跑一遍的习惯。比只看首行可靠得多因为首行正确、内部字段错乱的情况真的存在比如手动拼接过文件、或者传输时被 CRLF 污染。DER 格式是二进制cat出来是乱码一般用于跨语言调用、硬件加密机导入、或者直接塞进 Java 代码里当字节数组。转完之后建议做一次往返验证转成 DER 再转回来比对两个 PEM 文件的指纹。openssl pkcs8 -topk8 -nocrypt -in id_rsa -outform DER -out id_rsa_p8.der openssl pkey -inform DER -in id_rsa_p8.der -out id_rsa_p8_roundtrip.pem ssh-keygen -lf id_rsa_p8_roundtrip.pem3.3 转成 PuTTY 的 PPK 并在 Windows 上验证Windows 上赢 WinSCP、TortoiseGit、老版 FileZilla 基本只认 PPK。转换命令puttygen ~/.ssh/id_rsa -O private -o ~/.ssh/id_rsa.ppk如果源私钥是 OpenSSH 新格式且有密码PuTTY 0.68 以前的版本会提示无法识别得先升版本或先转成 PEM。转完一定要在 PuTTYgen 图形界面里加载一次看三件事顶部的算法和位数对不对、Key fingerprint跟ssh-keygen -lf出来的一致不一致、Key comment有没有保留。三者都对就说明这文件是好的。Comments字段在 PPK 里是可以随手改的它只是给人看的标签不影响认证。我一般把它改成部门-机器用途-到期日比如ops-batch-202606等半年后翻出来还能知道这钥匙干什么用比注释成rsa-key-20240101强太多。3.4 PPK v2 与 v3 的差异及回退PuTTY 0.75 之后默认生成 v3 格式的 PPK内部用 Argon2id 派生。安全性提升明显代价是兼容性崩了老版 WinSCP5.x 早期、旧 TortoiseGit、一些嵌入式工具链都读不了 v3报错类似unsupported PuTTY key format。回退办法有两种。一是直接把源私钥丢给老版本 puttygen 重新保存一次最省事。二是新版 puttygen 命令行里用--ppk-param指定参数具体支持的键值先跑puttygen --help看不同发行版打包的版本差异挺大我不建议把这个参数写死在脚本里。更稳的思路是保持 v2除非你确定下游工具的版本都够新。怎么判断手里的 ppk 是哪个版本看首行或者grep一下就知道了head -1 id_rsa.ppk # PuTTY-User-Key-File-3: ssh-rsa 即 v3 # PuTTY-User-Key-File-2: ssh-rsa 即 v23.5 Ed25519、ECDSA 私钥转换的边界在哪Ed25519 的问题是格式贫瘠。它能待的容器只有两个OpenSSH 自己的openssh-key-v1以及 PKCS#8 里 Ed25519 的对应结构OID 1.3.101.112。传统 PEM、PKCS#1、SEC1 里根本没有它的位置所以任何试图把它转成-----BEGIN RSA PRIVATE KEY-----或-----BEGIN EC PRIVATE KEY-----的操作都会失败。实践中我的原则很简单用 Ed25519 就接受它只能在 OpenSSH 生态里流转下游要 PEM 就换成 RSA。硬要 PKCS#8 形态可以借助 openssl 1.1.1 重建但过程繁琐且容易出错收益不值得。ECDSA 就宽松多了。ssh-keygen -t ecdsa生成的是 OpenSSH 新格式转 PEM 后会得到-----BEGIN EC PRIVATE KEY-----也就是 SEC1。要再转 PKCS#8ssh-keygen -p -m PEM -f id_ecdsa -N head -1 id_ecdsa # -----BEGIN EC PRIVATE KEY----- openssl pkcs8 -topk8 -nocrypt -in id_ecdsa -out id_ecdsa_p8.pem head -1 id_ecdsa_p8.pem # -----BEGIN PRIVATE KEY-----DSA 我只提一句OpenSSH 9.8 起默认不再支持ssh-dss新环境别再用它遇到了直接重新生成更省事。4. 公钥格式转换与落地authorized_keys、known_hosts 一起搞定4.1 从私钥反推公钥公钥丢了也不慌id_rsa.pub删了、手滑覆盖了不用重新生成密钥对。私钥里包含了推导公钥所需的全部信息ssh-keygen -y -f ~/.ssh/id_rsa ~/.ssh/id_rsa.pub如果私钥有密码会提示输入。这条命令有个细节导出的公钥不带注释末尾是空的而正常的.pub应该是ssh-rsa AAAA... userhost。这个注释字段只是给人看的不影响认证但很多平台GitHub、GitLab、云控制台在列表里靠它区分建议手动补上printf %s\n $(whoami)$(hostname) ~/.ssh/id_rsa.pub执行前确认私钥权限是600并且-y只对 RSA、ECDSA、Ed25519 有效DSA 已经不推荐了。4.2 OpenSSH 单行公钥与 RFC4716 互转这两种格式我遇到最多的场景是从某台交换机、路由器或者网管工具里导出的是 RFC4716 格式想合进authorized_keys反过来某些设备的导入界面只认 RFC4716手头只有单行公钥。# OpenSSH - RFC4716 ssh-keygen -e -m RFC4716 -f ~/.ssh/id_rsa.pub id_rsa_rfc4716.pub # RFC4716 - OpenSSH ssh-keygen -i -m RFC4716 -f id_rsa_rfc4716.pub id_rsa.pub-e是 export从 OpenSSH 格式导出成别的-i是 import从别的格式导入回 OpenSSH。方向别搞反反了会报is not a public key file。RFC4716 的一个好处是支持在头部加Comment:行有些设备的界面就靠这个字段做标注。但也要注意折行规则标准要求 base64 部分每行不超过 72 字符手动改文件时别把长行拼成一行某些严格实现的解析器会拒绝。4.3 转 SPKI/PEM 给 Java、云平台和证书体系用需要-----BEGIN PUBLIC KEY-----的场合其实不少云服务商控制台上传公钥、K8s 里存 Secret、Java 代码里加载公钥做验签、把 SSH 公钥塞进 X.509 证书。ssh-keygen -e -m PKCS8 -f ~/.ssh/id_rsa.pub id_rsa_spki.pem # 反向 ssh-keygen -i -m PKCS8 -f id_rsa_spki.pem id_rsa.pub这里-m PKCS8指的是公钥的 SubjectPublicKeyInfo 封装本地验证用openssl pkey -pubin -in id_rsa_spki.pem -text -noout它会打印模数、指数或者曲线名称和公钥点坐标。如果你手头还有旧格式的-----BEGIN RSA PUBLIC KEY-----PKCS#1 公钥转法略有不同openssl rsa -RSAPublicKey_in -in old_rsa_pub.pem -pubout -out spki_pub.pem4.4 把公钥可靠地写进 authorized_keys转换的最终目的多半是免密登录。标准姿势是ssh-copy-idssh-copy-id -i ~/.ssh/id_rsa.pub userhost它会自动创建.ssh目录、追加内容、设好权限比手搓可靠。但服务器做了 SSH 端口变更时要加-p某些精简系统没装这个脚本那就手动来ssh userhost mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/id_rsa.pub | ssh userhost cat ~/.ssh/authorized_keys ssh userhost chmod 600 ~/.ssh/authorized_keys千万别用覆盖authorized_keys那会把别人已有的公钥全冲掉团队共用的机器上这个操作能直接把人锁在外面。追加之后做个去重更整洁sort -u ~/.ssh/authorized_keys -o ~/.ssh/authorized_keysWindows 上没有ssh-copy-id用 PowerShell 或者 Git Bash 都能做type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh userhost cat ~/.ssh/authorized_keys写完验证的方式是ssh -vvv userhost输出里重点看两行debug1: Offering public key: ...表示客户端把公钥递过去了Authentications that can continue: publickey,password如果还留着password就说明 publickey 没被接受需要回到权限和配置上查。4.5 known_hosts 也是一种公钥格式别忽略了严格说known_hosts存的不是你的密钥是服务器的 host key但转换逻辑和排查思路是一脉相承的而且是同类文件里最容易被格式问题绊倒的。预填充一批机器的 host keyssh-keyscan -H -t rsa,ecdsa,ed25519 host1 host2 ~/.ssh/known_hosts-H会把主机名做 HMAC 哈希避免文件泄露时暴露内网拓扑。查询某台机器记录ssh-keygen -F host1 -f ~/.ssh/known_hosts删除某台机器记录最常用的操作ssh-keygen -R host1服务器重装系统、扩容换实例之后客户端会报WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED这时候先确认是正常的机器重建还是中间人风险确认无误再用-R删掉旧记录重连。切忌盲目全局设置StrictHostKeyChecking no那等于把这道校验永久关上。5. 典型报错与排查实录5.1 JSch 抛 invalid privatekey报错长这样com.jcraft.jsch.JSchException: invalid privatekey: [B5d1a4b3f。原因基本逃不出三条私钥是 OpenSSH 新格式、私钥是 Ed25519、私钥是 PPK。老版 JSch0.1.54 及以前只认 PKCS#1 的 RSA。处理方式分两条路。省事的一条是转格式转成 PKCS#1cp id_rsa id_rsa.bak ssh-keygen -p -m PEM -f id_rsa -N 另一条是换库用社区维护的 forkdependency groupIdcom.github.mwiede/groupId artifactIdjsch/artifactId version0.2.17/version /dependency这个 fork 支持 OpenSSH 新格式和 Ed25519API 基本兼容原版替换成本很低。我现在的项目一律直接用 fork省掉转格式这一步。顺带说一个容易绕进去的点Java 代码对接 SFTP 只需要私钥公钥是给服务器那边核对用的。如果手头只有公钥是没办法建立公钥认证连接的必须拿到私钥或者重新生成一对并把新公钥传上去。有些同事从云控制台下载时只下了.pub然后问为什么连不上就是这个问题。5.2 Paramiko 不认识 Ed25519Paramiko 2.2 以前不支持 Ed25519报错类似SSHException: Invalid key (class: Ed25519Key)或者更隐晦的not a valid RSA private key file。升级依赖就能解决pip install -U paramiko cryptography pynaclParamiko 也完全不认 PPK喂进去会报not a valid ... key file必须先用puttygen转成 OpenSSH 或 PEM。还有一个信号值得留意Paramiko 对用aes256-cbc加密的 OpenSSH 私钥支持有限遇到读取失败可以先把私钥密码清掉试试确认是算法兼容问题再决定是换加密方式还是换库。按密钥类型选对应的加载方法别混着用import paramiko # OpenSSH 格式的 RSA key paramiko.RSAKey.from_private_key_file(/path/id_rsa, passwordxxx) # Ed25519 key paramiko.Ed25519Key.from_private_key_file(/path/id_ed25519, passwordxxx)5.3 转换完却登录不上权限、SELinux 与 StrictModes这是最气人的一类问题格式明明转对了指纹也一致就是连不上。按下面的顺序查命中率很高。先看权限。私钥必须600~/.ssh必须700authorized_keys必须600。权限过松时 sshd 会静默拒绝使用这个文件日志里可能只有一行很不起眼的提示chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys ~/.ssh/id_rsa再看StrictModes。服务端sshd_config里StrictModes yes默认值会要求家目录、.ssh、authorized_keys都不能被组或其他用户写。有些系统建用户时家目录是775这时候公钥认证就会被拒。第三看 SELinux。把文件从别的机器拷贝过来上下文可能变成user_home_t而不是ssh_home_t同样会导致认证失败restorecon -Rv ~/.ssh ls -Z ~/.ssh第四看服务端配置。PubkeyAuthentication yes有没有被注释掉或者设成noAuthorizedKeysFile是不是被改到了非默认路径。改完记得sshd -t检查语法再systemctl reload sshd语法错了重载会直接失败。最后看算法兼容。OpenSSH 8.8 起服务端默认禁用 SHA-1 签名老客户端用ssh-rsa连新服务器就会失败。客户端侧临时加# ~/.ssh/config Host oldhost PubkeyAcceptedAlgorithms ssh-rsa服务端侧则是# /etc/ssh/sshd_config PubkeyAcceptedAlgorithms ssh-rsa这只是兼容手段长期方案是换成 Ed25519 或者至少用rsa-sha2-256签名。我在新项目上一律直接上 Ed25519省掉这一整类问题。5.4 常见问题速查表现象大概率原因处理invalid privatekeyOpenSSH 新格式 / Ed25519 / PPK 喂给了老 JSch转 PKCS#1或换 mwiede forknot a valid RSA private key fileParamiko 读到 PPK 或加密格式不支持puttygen 转 OpenSSH 后重试Permissions 0644 for id_rsa are too open私钥权限过松chmod 600 id_rsa转换后指纹变了操作对象错了或生成了新密钥停止使用重新核对来源服务器报Authentication refused: bad ownership家目录或.ssh组可写收紧权限检查 StrictModesREMOTE HOST IDENTIFICATION HAS CHANGED服务器 host key 变了ssh-keygen -R host后重连确认unsupported PuTTY key formatPPK v3 喂给老工具用老 puttygen 重存为 v2error: invalid format转 Ed25519 为 PEM传统 PEM 无 Ed25519 结构保持 OpenSSH 格式或换 RSAno mutual signature algorithm对端禁用了ssh-rsa临时ssh-rsa长期换 Ed255196. 我平时的一些习惯做法第一件事永远是cp一份带日期后缀的备份再动手。ssh-keygen -p是原地覆盖没有后悔药。备份文件名我统一用id_rsa.bak.20260601这种格式既看得懂排序也方便清理。转换完立刻用ssh-keygen -lf和openssl pkey -check双重验证两条都过再删备份。第二件是把密钥的指纹单独记一份。我习惯在密钥目录里放个README写清楚生成时间、算法位数、指纹、用途、到期日。密钥轮换的时候对着这份清单操作不会漏掉某个下游系统。转格式不会改变指纹这句话记住之后凡是遇到转完指纹变了的情况第一反应就该是停下来核对而不是继续往下走。第三件是能用 Ed25519 就别用 RSA。新环境生成密钥直接用ssh-keygen -t ed25519 -a 100-a控制 KDF 轮数值大一点更抗暴力破解。唯一的代价是遇到老 Java 库时要换库或者转格式但这个成本随着各语言生态更新只会越来越低。第四件是私钥只在需要它的机器上出现.pub随便传私钥永远走安全通道。转格式的过程中会产生临时文件脚本里记得trap清理或者用完手动rm。我见过临时目录里躺着一把没密码的私钥被find /tmp -name *rsa*扫出来那种感觉挺糟糕的。最后要转公钥给某个平台用先看清楚它要的是单行 OpenSSH、RFC4716 还是 PEM。三种格式长得完全不一样猜错一次至少要返工一轮head -1看一眼目标平台的示例就能省下这轮返工。
阅读完成 · 觉得有帮助?
咨询建站