我正在使用以下代码在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;
}
但仍然得到“无效的私钥”例外。
我也偶然发现了这个问题。在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
最新版本的OpenSSH(7.8和更新版本)默认生成新的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)。加载密钥,然后转到Conversions> Export OpenSSH密钥。对于RSA密钥,它将使用经典格式。
如果要使用ssh-keygen
创建新密钥,只需添加-m PEM
以生成经典格式的新密钥:
ssh-keygen -m PEM
.pem
和de-base64的文件并将结果视为PKCS8-unncrypted,显然是成功的。这意味着该文件不是PEM格式。 PEM格式至少必须使dash-BEGIN和dash-END行有效,如果不删除则导致de-base64失败或错误。 (有些PEM格式也有822样式的标题,必须处理。)PKCS8Generator
构造函数只接受RSAPrivateKey
。最接近的是JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)
(即一个不同但相关的类,两个参数不是一个)。PemWriter
是缓冲的,你在查看底层的StringWriter
之前没有冲洗它。因此,writer.toString().getBytes()
是一个空/零长度数组,JSch
正确认为无效。#2和#3修复并使用我的输入,并直接调用JSch
而不是通过JGit
,它适用于我。