"Недействительный приватный ключ" при использовании JSch
Я использую следующий код для работы с Git в приложении Java. У меня есть действительный ключ (используйте его постоянно), и этот конкретный код уже работал для меня с тем же ключом и git-репозиторием, но теперь я получаю следующее исключение:
неверный приватный ключ: [B @59c40796.
На этой линии:
jSch.addIdentity("<key_path>/private_key.pem");
Мой полный код:
String remoteURL = "ssh://[email protected]<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;
}
Но все равно получаю исключение "неверный приватный ключ".
Ответы
Ответ 1
Я тоже наткнулся на эту проблему. при запуске Jgit на 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: [[email protected]
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
) ssh-keygen -t rsa
исключение.
Отредактируйте следующие комментарии: Если у вас OpenSSH 7.8 и выше, вам может понадобиться добавить -m PEM в команду генерации: ssh-keygen -t rsa -m PEM
Ответ 2
Последние версии 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). Загрузите ключ и перейдите в "Преобразования"> "Экспорт ключа OpenSSH". Для ключей RSA будет использоваться классический формат.
Если вы создаете новый ключ с помощью ssh-keygen
, просто добавьте -m PEM
чтобы сгенерировать новый ключ в классическом формате:
ssh-keygen -m PEM
Ответ 3
-
Вы читаете файл с именем .pem
и де-base64 все это и обрабатываете результат как PKCS8-незашифрованный, по-видимому, успешно. Это означает, что файл НЕ был PEM-форматом. Формат PEM как минимум ДОЛЖЕН иметь действительные строки dash-BEGIN и dash-END, которые, если их не удалить, приводят к тому, что de-base64 либо дает сбой, либо ошибается. (Некоторые форматы PEM также имеют заголовки в стиле 822, которые должны обрабатываться.)
-
Вы, кажется, используете BouncyCastle, но в моих версиях нет конструктора PKCS8Generator
который принимает только RSAPrivateKey
. Самое близкое, что работает, это JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)
(т. JcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)
но связанный класс и два аргумента, а не один).
-
PemWriter
буферизован, и вы не StringWriter
его, прежде чем посмотреть на базовый StringWriter
. В результате writer.toString().getBytes()
- это пустой массив нулевой длины, который JSch
справедливо считает недействительным.
С исправленными # 2 и # 3 и использованием моего ввода и вызовом JSch
напрямую, а не через JGit
, это работает для меня.