"Invalid privatekey" 使用 JSch 时
"Invalid privatekey" when using JSch
我正在使用以下代码在 Java 应用程序中使用 Git。
我有一个有效的密钥(一直使用它),并且此特定代码之前使用相同的密钥和 git 存储库对我有用,但现在我得到以下异常:
invalid privatekey: [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;
}
但仍然出现 "invalid privatekey" 异常。
您读取了一个名为 .pem
的文件并将其 de-base64 all 并将结果视为未加密的 PKCS8,显然是成功的。这意味着该文件不是 PEM-format。 PEM 格式至少必须有 dash-BEGIN 和 dash-END 行是有效的,如果不删除它们会导致 de-base64 失败或错误。 (一些 PEM 格式也有 822 样式 headers 必须处理。)
您似乎在使用 BouncyCastle,但在我的版本中没有仅采用 RSAPrivateKey
的 PKCS8Generator
构造函数。最接近的是 JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)
(即不同但相关的 class,两个参数不是一个)。
PemWriter
已缓冲,您在查看底层 StringWriter
之前没有刷新它。结果 writer.toString().getBytes()
是一个 empty/zero-length 数组,JSch
正确地认为它无效。
修复#2 和#3 并使用我的输入,并直接调用 JSch
而不是通过 JGit
,它对我有用。
我也偶然发现了这个问题。
运行 Jgit on mac,对于某些用户,我们看到了以下异常:
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 的用户身上,它输出此密钥 header:
-----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 及更新版本)默认以 new OpenSSH 格式生成密钥,其开头为:
-----BEGIN OPENSSH PRIVATE KEY-----
JSch 不支持这种密钥格式。
您可以使用 ssh-keygen
将密钥转换为 经典 OpenSSH 格式:
ssh-keygen -p -f file -m pem -P passphrase -N passphrase
(如果密钥未使用密码加密,请使用 ""
而不是 passphrase
)
对于 Windows 用户:请注意 ssh-keygen.exe
现在内置于 Windows 10/11 中。对于 Windows.
的旧版本,可以是 downloaded from Microsoft Win32-OpenSSH project
在 Windows 上,您还可以使用 PuTTYgen(来自 PuTTY package):
- 启动 PuTTYgen
- 加载密钥
- 转到转换 > 导出 OpenSSH 密钥。
对于 RSA 密钥,它将使用 经典 格式。
如果您使用 ssh-keygen
创建新密钥,只需添加 -m PEM
即可生成 经典 格式的新密钥:
ssh-keygen -m PEM
JSch 不支持这种密钥格式。它仅支持 RSAPrivateKey。
这个命令对我有用。试试这个解决方案
ssh-keygen -m PEM -t rsa -b 2048
//编辑为 2048 密钥大小的 rsa
很晚才回复,但想留下如何面对问题的线索。
正如许多人提到的那样,重点实际上是您生成密钥的方式以及使用 -m PEM
选项解析的方式。
然而,如果像我一样,由于 public 部分已经安装在多个服务器中,您无法重新生成密钥,您仍然可以将您的私钥转换为合适的格式。
为此,只需发出以下命令:
ssh-keygen -p -m pem -f id_rsa
它将要求输入新密码。使用参数 -P
(旧密码)和 -N
(新密码),如果需要,您可以立即提供它们。
除了将 OPENSSH
密钥格式转换为原始 JSch 支持的格式,您还可以切换到 JSch 的分支,您可以在 https://github.com/mwiede/jsch
找到
您只需将 JSch Maven 坐标替换为 com.github.mwiede:jsch:0.1.61
。
分支确实支持 OPENSSH
密钥格式和更多算法,这在未来可能会变得很重要,因为 OpenSSH 服务器会将允许的算法集限制为最安全的算法集。
我想补充一点,为了避免以下情况 headers 您需要使用
创建密钥
-C "any-comment"
Headers 将从私钥中删除:
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,3551DFC375229D5758289E8D366082FE
只剩下
-----BEGIN RSA PRIVATE KEY-----
YOUR_KEY_HERE
-----END RSA PRIVATE KEY-----
我正在使用以下代码在 Java 应用程序中使用 Git。 我有一个有效的密钥(一直使用它),并且此特定代码之前使用相同的密钥和 git 存储库对我有用,但现在我得到以下异常:
invalid privatekey: [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;
}
但仍然出现 "invalid privatekey" 异常。
您读取了一个名为
.pem
的文件并将其 de-base64 all 并将结果视为未加密的 PKCS8,显然是成功的。这意味着该文件不是 PEM-format。 PEM 格式至少必须有 dash-BEGIN 和 dash-END 行是有效的,如果不删除它们会导致 de-base64 失败或错误。 (一些 PEM 格式也有 822 样式 headers 必须处理。)您似乎在使用 BouncyCastle,但在我的版本中没有仅采用
RSAPrivateKey
的PKCS8Generator
构造函数。最接近的是JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)
(即不同但相关的 class,两个参数不是一个)。PemWriter
已缓冲,您在查看底层StringWriter
之前没有刷新它。结果writer.toString().getBytes()
是一个 empty/zero-length 数组,JSch
正确地认为它无效。
修复#2 和#3 并使用我的输入,并直接调用 JSch
而不是通过 JGit
,它对我有用。
我也偶然发现了这个问题。 运行 Jgit on mac,对于某些用户,我们看到了以下异常:
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 的用户身上,它输出此密钥 header:
-----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 及更新版本)默认以 new OpenSSH 格式生成密钥,其开头为:
-----BEGIN OPENSSH PRIVATE KEY-----
JSch 不支持这种密钥格式。
您可以使用 ssh-keygen
将密钥转换为 经典 OpenSSH 格式:
ssh-keygen -p -f file -m pem -P passphrase -N passphrase
(如果密钥未使用密码加密,请使用 ""
而不是 passphrase
)
对于 Windows 用户:请注意 ssh-keygen.exe
现在内置于 Windows 10/11 中。对于 Windows.
在 Windows 上,您还可以使用 PuTTYgen(来自 PuTTY package):
- 启动 PuTTYgen
- 加载密钥
- 转到转换 > 导出 OpenSSH 密钥。
对于 RSA 密钥,它将使用 经典 格式。
如果您使用 ssh-keygen
创建新密钥,只需添加 -m PEM
即可生成 经典 格式的新密钥:
ssh-keygen -m PEM
JSch 不支持这种密钥格式。它仅支持 RSAPrivateKey。 这个命令对我有用。试试这个解决方案
ssh-keygen -m PEM -t rsa -b 2048
//编辑为 2048 密钥大小的 rsa
很晚才回复,但想留下如何面对问题的线索。
正如许多人提到的那样,重点实际上是您生成密钥的方式以及使用 -m PEM
选项解析的方式。
然而,如果像我一样,由于 public 部分已经安装在多个服务器中,您无法重新生成密钥,您仍然可以将您的私钥转换为合适的格式。
为此,只需发出以下命令:
ssh-keygen -p -m pem -f id_rsa
它将要求输入新密码。使用参数 -P
(旧密码)和 -N
(新密码),如果需要,您可以立即提供它们。
除了将 OPENSSH
密钥格式转换为原始 JSch 支持的格式,您还可以切换到 JSch 的分支,您可以在 https://github.com/mwiede/jsch
您只需将 JSch Maven 坐标替换为 com.github.mwiede:jsch:0.1.61
。
分支确实支持 OPENSSH
密钥格式和更多算法,这在未来可能会变得很重要,因为 OpenSSH 服务器会将允许的算法集限制为最安全的算法集。
我想补充一点,为了避免以下情况 headers 您需要使用
创建密钥-C "any-comment"
Headers 将从私钥中删除:
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,3551DFC375229D5758289E8D366082FE
只剩下
-----BEGIN RSA PRIVATE KEY-----
YOUR_KEY_HERE
-----END RSA PRIVATE KEY-----