web-dev-qa-db-ja.com

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

しかし、まだ"invalid privatekey"例外が発生しています。

17
o_b7

私もこの問題に出くわしました。 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、このキーヘッダーを出力します。

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

種類の代わりに[〜#〜] rsa [〜#〜]

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

rSAキーの再生成(ssh-keygen -t rsa)、例外をなくしました。

次のコメントを編集します。OpenSSH7.8以降を使用している場合は、生成コマンドに-m PEMを追加する必要がある場合があります。ssh-keygen -t rsa -m PEM

21
Natan

OpenSSHの最近のバージョン(7.8以降)は、デフォルトでnewOpenSSH形式でキーを生成します。

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

JSchはこのキー形式をサポートしていません。


ssh-keygen を使用して、キーをclassicOpenSSH形式に変換できます。

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

(キーがパスフレーズで暗号化されていない場合、passphraseの代わりに""を使用します)


Windowsを使用している場合、PuTTYgenを使用できます( PuTTYパッケージ から)。キーをロードして、Conversions> Export OpenSSH keyに移動します。 RSAキーの場合、classic形式を使用します。


ssh-keygenを使用して新しいキーを作成する場合は、 -m PEM を追加して、classic形式:

ssh-keygen -m PEM
13
Martin Prikryl
  1. _.pem_およびde-base64 allという名前のファイルを読み取り、結果をPKCS8-unencryptedとして扱い、明らかに成功します。これは、ファイルがPEM形式ではなかったことを意味します。 PEM形式では、少なくともdash-BEGIN行とdash-END行が有効である必要があります。削除しないと、de-base64が失敗するか間違っています。 (一部 PEM形式には、処理が必要な822形式のヘッダーもあります。)

  2. BouncyCastleを使用しているように見えますが、私のバージョンではRSAPrivateKeyのみを受け取る_PKCS8Generator_コンストラクターはありません。最も機能するのはJcaPKCS8Generator (RSAPrivateKey implements PrivateKey, OutputEncryptor=null)(つまり、異なるが関連するクラスであり、2つの引数は1つではありません)です。

  3. PemWriterはバッファリングされ、基礎となるStringWriterを見る前にフラッシュしませんでした。結果として、writer.toString().getBytes()は空/ゼロ長の配列であり、JSchは正しく無効と見なします。

#2と#3を修正し、入力を使用し、JSchを経由せずにJGitを直接呼び出すと、うまくいきます。

0