如何使用Java将SSH2私钥转换为RSA格式以适配JSch库?
解决JSch不支持SSH2格式私钥的自动转换问题
我之前也碰到过一模一样的问题!JSch确实只认OpenSSH格式的私钥,而Tectia生成的SSH2格式(带---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----头)根本没法直接用。手动用PuttyGen转换太麻烦,要在Java里自动搞定这个事,我们可以借助BouncyCastle库来解析SSH2密钥,再转成JSch能识别的OpenSSH RSA格式。
步骤1:添加依赖
首先得引入BouncyCastle的相关包,Maven项目可以直接加这段依赖:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency>
步骤2:编写转换代码
核心逻辑很清晰:读取SSH2密钥文件 → 用BouncyCastle解析(处理加密密码)→ 转成OpenSSH格式字符串 → 直接给JSch用或者存成文件。
下面是完整的可运行代码:
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import java.io.BufferedReader; import java.io.FileReader; import java.io.StringReader; import java.security.KeyPair; import java.security.PrivateKey; import java.security.Security; public class SSH2ToOpenSSHConverter { static { // 注册BouncyCastle安全提供者 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } /** * 将SSH2加密私钥转换为OpenSSH RSA格式私钥字符串 * @param ssh2KeyPath SSH2私钥文件路径 * @param passphrase 密钥密码(无密码传null) * @return OpenSSH格式的私钥字符串 * @throws Exception 转换过程中的异常 */ public static String convertSSH2ToOpenSSH(String ssh2KeyPath, String passphrase) throws Exception { // 读取SSH2密钥文件内容 StringBuilder ssh2KeyContent = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(ssh2KeyPath))) { String line; while ((line = reader.readLine()) != null) { ssh2KeyContent.append(line).append("\n"); } } // 解析SSH2密钥 PEMParser pemParser = new PEMParser(new StringReader(ssh2KeyContent.toString())); Object obj = pemParser.readObject(); pemParser.close(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); KeyPair keyPair; if (obj instanceof PEMEncryptedKeyPair) { // 处理加密的密钥 PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) obj; PEMDecryptorProvider decryptorProvider = new JcePEMDecryptorProviderBuilder() .build(passphrase.toCharArray()); keyPair = converter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptorProvider)); } else { // 处理未加密的密钥 PEMKeyPair pemKeyPair = (PEMKeyPair) obj; keyPair = converter.getKeyPair(pemKeyPair); } // 将私钥转换为OpenSSH格式 PrivateKey privateKey = keyPair.getPrivate(); PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); byte[] openSSHKeyBytes = org.bouncycastle.openssl.jcajce.JcaPEMWriter.writeObject(privateKeyInfo); // 替换头尾部,适配JSch的RSA格式要求 String openSSHKey = new String(openSSHKeyBytes) .replace("-----BEGIN PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----") .replace("-----END PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----"); return openSSHKey; } // 测试示例 public static void main(String[] args) throws Exception { String ssh2KeyPath = "/path/to/your/tectia_ssh2_key"; String passphrase = "your_key_password"; // 无密码则传null String openSSHKey = convertSSH2ToOpenSSH(ssh2KeyPath, passphrase); // 直接把转换后的密钥交给JSch使用 com.jcraft.jsch.JSch jsch = new com.jcraft.jsch.JSch(); jsch.addIdentity("converted_rsa_key", openSSHKey.getBytes(), null, passphrase != null ? passphrase.getBytes() : null); // 后续的SFTP连接逻辑... } }
关键细节说明
- BouncyCastle的作用:它是唯一能直接解析SSH2格式PEM密钥的Java库,不管密钥是加密还是明文的都能处理。
- 格式适配:BouncyCastle默认生成的是PKCS#8格式私钥,我们需要把头尾替换成RSA专属的标识,JSch才能正确识别。
- 密码处理:如果你的SSH2密钥是加密的,一定要传入正确的密码,否则解析会直接失败。
验证转换结果
转换完成后,可以把字符串存成文件,用ssh-keygen -y -f converted_key命令验证,如果能正常输出对应的公钥,就说明转换成功了。
内容的提问来源于stack exchange,提问作者Limmy
相关产品推荐
相关产品推荐

