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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53134212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:43:35  来源:igfitidea点击:

"Invalid privatekey" when using JSch

javasshjsch

提问by o_b7

I'm using the following code to work with Git in a Java application. I have a valid key (use it all the time), and this specific code has work for me before with the same key and git repository, but now I get the following exception:

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

invalid privatekey: [B@59c40796.

无效的私钥:[B@59c40796。

At this line:

在这一行:

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

My full code:

我的完整代码:

    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;
        }
    };

After searching online, I've change createDefaultJSch to use pemWriter:

在线搜索后,我将 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;
}

But still getting "invalid privatekey"exception.

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

采纳答案by Natan

I also stumbled upon this issue. running Jgiton mac, for some users we saw the following exception:

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

The root cause was discovered to be the ssh private key mismatch. The exception only happened for users with key of newer kind ed25519, which outputs this key header:

发现根本原因是 ssh 私钥不匹配。异常只发生在具有更新类型ed25519密钥的用户身上,它输出这个密钥头:

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

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

instead of kind RSA:

而不是那种RSA

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

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

regenerating an RSA key (ssh-keygen -t rsa), made the exception go away.

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

Edit following comments: If you have OpenSSH 7.8 and above you might need to add -m PEM to the generation command: ssh-keygen -t rsa -m PEM

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

回答by dave_thompson_085

  1. You read a file named .pemand de-base64 allof it and treat the result as PKCS8-unencrypted, apparently successfully. This means the file was NOT PEM-format. PEM format at minimum MUST have the dash-BEGIN and dash-END lines to be valid, which if not removed cause de-base64 to either fail or be wrong. (SomePEM formats also have 822-style headers which must be handled.)

  2. You appear to be using BouncyCastle, but in my versions there is no PKCS8Generatorconstructor that takes only RSAPrivateKey. The closest thing that works is JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)(i.e. a different but related class, and two arguments not one).

  3. PemWriteris buffered, and you didn't flush it before looking at the underlying StringWriter. As a result writer.toString().getBytes()is an empty/zero-length array, which JSchrightly considers invalid.

  1. 你读一个文件名为.pem和的base64去所有的它,并把结果作为PKCS8未加密,显然是成功的。这意味着该文件不是 PEM 格式。PEM 格式至少必须有 dash-BEGIN 和 dash-END 行是有效的,如果不删除会导致 de-base64 失败或错误。(某些PEM 格式还具有必须处理的 822 样式的标头。)

  2. 您似乎在使用 BouncyCastle,但在我的版本中,没有PKCS8Generator构造函数只需要RSAPrivateKey. 最接近的工作是JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)(即一个不同但相关的类,两个参数不是一个)。

  3. PemWriter已缓冲,并且您在查看底层StringWriter. 结果writer.toString().getBytes()是一个空/零长度数组,JSch正确地认为无效。

With #2 and #3 fixed and using my input, and calling JSchdirectly instead of via JGit, it works for me.

修复 #2 和 #3 并使用我的输入,并JSch直接调用而不是 via JGit,它对我有用。

回答by Martin Prikryl

Recent versions of OpenSSH (7.8 and newer) generate keys in newOpenSSH format by default, which start with:

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

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

JSch does not support this key format.

JSch 不支持这种密钥格式。



You can use ssh-keygento convert the key to the classicOpenSSH format:

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

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

(if the key is not encrypted with a passphrase, use ""instead of passphrase)

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

For Windows users: Note that ssh-keygen.exeis now built-in in Windows 10. And can be downloaded from Microsoft Win32-OpenSSH projectfor older versions of Windows.

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



On Windows, you can also use PuTTYgen (from PuTTY package):

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

  • Start PuTTYgen
  • Load the key
  • Go to Conversions > Export OpenSSH key.
    For RSA keys, it will use the classicformat.
  • 启动 PuTTYgen
  • 加载密钥
  • 转至转换 > 导出 OpenSSH 密钥
    对于 RSA 密钥,它将使用经典格式。


If you are creating a new key with ssh-keygen, just add -m PEMto generate the new key in the classicformat:

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

ssh-keygen -m PEM

回答by Ananth Kumar

JSch does not support this key format. It supports only RSAPrivateKey. This command works for me. Try this solution

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

ssh-keygen -m PEM -t rsa -b 2048

//edited to rsa with 2048 keysize

//编辑为2048密钥大小的rsa