使用 JSch 时出现“无效私钥”

新手上路,请多包涵

我正在使用以下代码在 Java 应用程序中使用 Git。我有一个有效的密钥(一直使用它),这个特定的代码之前使用相同的密钥和 git 存储库对我有用,但现在我得到以下异常:

私钥无效:[B@59c40796。

在这一行:

 jSch.addIdentity("<key_path>/private_key.pem");

我的完整代码:

     String remoteURL = "ssh://git@<git_repository>";
    TransportConfigCallback transportConfigCallback = new SshTransportConfigCallback();
    File gitFolder = new File(workingDirectory);
    if (gitFolder.exists()) FileUtils.delete(gitFolder, FileUtils.RECURSIVE);

    Git git = Git.cloneRepository()
            .setURI(remoteURL)
            .setTransportConfigCallback(transportConfigCallback)
            .setDirectory(new File(workingDirectory))
            .call();
}

private static class SshTransportConfigCallback implements TransportConfigCallback {
    private final SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
        @Override
        protected void configure(OpenSshConfig.Host hc, Session session) {
            session.setConfig("StrictHostKeyChecking", "no");
        }

        @Override
        protected JSch createDefaultJSch(FS fs) throws JSchException {
            JSch jSch = super.createDefaultJSch(fs);
            jSch.addIdentity("<key_path>/private_key.pem");

            return jSch;
        }
    };

在线搜索后,我将 createDefaultJSch 更改为使用 pemWriter:

 @Override
protected JSch createDefaultJSch(FS fs) throws JSchException {
    JSch jSch = super.createDefaultJSch(fs);
    byte[] privateKeyPEM = null;

    try {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        List<String> lines = Files.readAllLines(Paths.get("<my_key>.pem"), StandardCharsets.US_ASCII);
        PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(String.join("", lines)));
        RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);

        PKCS8Generator pkcs8 = new PKCS8Generator(privKey);

        StringWriter writer = new StringWriter();
        PemWriter pemWriter = new PemWriter(writer);
        pemWriter.writeObject(pkcs8);

        privateKeyPEM = writer.toString().getBytes("US-ASCII");

    } catch (Exception e) {
        e.printStackTrace();
    }

    jSch.addIdentity("git", privateKeyPEM, null, null);

    return jSch;
}

但仍然收到 “无效私钥” 异常。

原文由 o_b7 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.8k
2 个回答

我也偶然发现了这个问题。在 mac 上运行 Jgit ,对于某些用户,我们看到以下异常:

 org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:160)
    at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:137)
    at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:274)
    at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:169)
    at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:136)
    at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:122)
    at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1236)
    at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:234)
    ... 17 more
Caused by: com.jcraft.jsch.JSchException: invalid privatekey: [B@e4487af
    at com.jcraft.jsch.KeyPair.load(KeyPair.java:664)
    at com.jcraft.jsch.KeyPair.load(KeyPair.java:561)
    at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
    at com.jcraft.jsch.JSch.addIdentity(JSch.java:407)
    at com.jcraft.jsch.JSch.addIdentity(JSch.java:367)
    at org.eclipse.jgit.transport.JschConfigSessionFactory.getJSch(JschConfigSessionFactory.java:276)
    at org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(JschConfigSessionFactory.java:220)
    at org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(JschConfigSessionFactory.java:176)
    at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:110)

发现根本原因是ssh私钥不匹配。异常仅发生在使用较新类型 ed25519 密钥的用户身上,该密钥输出此密钥标头:

-----BEGIN OPENSSH PRIVATE KEY-----

而不是那种 RSA

-----BEGIN RSA PRIVATE KEY-----

重新生成 RSA 密钥 ( ssh-keygen -t rsa ),使异常消失。

编辑以下评论:如果您有 OpenSSH 7.8 及更高版本,您可能需要将 -m PEM 添加到生成命令中: ssh-keygen -t rsa -m PEM

原文由 Natan 发布,翻译遵循 CC BY-SA 4.0 许可协议

默认情况下,最新版本的 OpenSSH(7.8 和更新版本)以 的 OpenSSH 格式生成密钥,其开头为:

 -----BEGIN OPENSSH PRIVATE KEY-----

JSch 不支持这种密钥格式。


您可以使用 ssh-keygen 将密钥转换为 经典 的 OpenSSH 格式:

 ssh-keygen -p -f <privateKeyFile> -m pem -P passphrase -N passphrase

这个“滥用” -p (更改密码)命令。它将使用 经典 OpenSSH 格式 ( pem ) 的新私钥覆盖由 -f 选项标识的私钥文件。您可以将当前密码保留为新密码。如果密钥未使用密码加密,请使用 "" 而不是 passphrase 。之后,您可以使用 ssh-keygen -y -e -f <privateKeyFile> >temp.pub 比较公钥并验证现有公钥是否适用于新格式的私钥。

对于 Windows 用户:请注意 ssh-keygen.exe 现在内置于 Windows 1011 中。并且可以从适用于旧版本 Windows 的 Microsoft Win32-OpenSSH 项目 下载。


在 Windows 上,您还可以使用 PuTTYgen(来自 PuTTY 包):

  • 启动 PuTTYgen
  • 加载密钥
  • 转到 Conversions > Export OpenSSH key

对于 RSA 密钥,它将使用 经典 格式。


如果您使用 ssh-keygen 创建新密钥,只需添加 -m PEM 即可生成 经典 格式的新密钥:

 ssh-keygen -m PEM


实际上,原来的 JSch 似乎不再被积极维护。特别是,如果您要开始新项目,它可能不是最好的开始库。如今,JSch 存在许多兼容性问题。对于一些重要的,请参阅:

相反,您可以考虑使用这个 JSch 分支:

https://github.com/mwiede/jsch

其中,它确实支持新的 OpenSSH 密钥格式。

原文由 Martin Prikryl 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题