使用JSch时“无效私钥”

时间:2018-11-03 18:17:54

标签: java ssh 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;
}

但仍然出现“无效私钥” 异常。

6 个答案:

答案 0 :(得分:14)

我也偶然发现了这个问题。 在 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

答案 1 :(得分:5)

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

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

JSch不支持此密钥格式。


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

ssh-keygen -p -f file -m pem -P passphrase -N passphrase

(如果密钥未使用密码加密,请使用""代替passphrase


如果您使用的是Windows,则可以使用PuTTYgen(来自PuTTY package)。加载密钥,然后转到转化>导出OpenSSH密钥。对于RSA密钥,它将使用经典格式。


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

ssh-keygen -m PEM

答案 2 :(得分:3)

除了将 OPENSSH 键格式转换为原始 JSch 支持的格式之外,您还可以切换到 JSch 的一个分支,您可以在 https://github.com/mwiede/jsch 处找到该格式

您只需将您的 JSch Maven 坐标替换为 com.github.mwiede:jsch:0.1.61

分叉确实支持 OPENSSH 密钥格式和更多算法,这在未来可能会变得很重要,因为 OpenSSH 服务器会将允许的算法集限制为最安全的算法集。

答案 3 :(得分:1)

回复很晚,但想留下如何面对问题的答案。

正如前面提到的,要点实际上是生成密钥并使用-m PEM选项解决的方式。

但是,就像我一样,由于公共部分已经安装在多个服务器上而无法重新生成密钥,您仍然可以将私钥转换为合适的格式。

为此,只需发出以下命令:

ssh-keygen -p -m pem -f id_rsa

它将要求输入新的密码。使用参数-P(旧密码)和-N(新密码),您可以根据需要立即提供它们。

答案 4 :(得分:0)

  1. 您读取了一个名为.pem的文件,并对文件进行了de-base64 all 的处理,并将结果视为未加密的PKCS8,显然很成功。这意味着该文件不是PEM格式。 PEM格式至少必须具有破折号-BEGIN和破折号-END行,否则如果未删除它们,将导致de-base64失败或出错。 (某些 PEM格式还具有必须处理的822样式的标头。)

  2. 您似乎正在使用BouncyCastle,但在我的版本中,没有PKCS8Generator构造函数仅占用RSAPrivateKey。最有效的方法是JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)(即,一个不同但相关的类,两个参数不是一个)。

  3. PemWriter已被缓冲,在查看基础StringWriter之前您没有刷新它。结果,writer.toString().getBytes()是一个空/零长度的数组,JSch正确地认为是无效的。

固定#2和#3并使用我的输入,然后直接调用JSch而不是通过JGit来调用它,

答案 5 :(得分:0)

JSch不支持此密钥格式。它仅支持RSAPrivateKey。 此命令对我有用。试试这个解决方案

.md

///已编辑为2048键大小的rsa