JSCH - 私钥无效

17

我正在使用netbeans 7.2运行JDK 1.7和Windows 7。我使用putty-keygen生成了一个SSH私钥和公钥对(SSH2-2048位)。我的私钥没有密码。我现在正在尝试使用SFTP连接到一台主机,但是当我传递私钥(ppk)来设置身份验证时,代码返回无效的私钥错误。我在WinSCP中使用相同的私钥连接到同一台主机并且它工作正常。请帮助我解决这个错误。以下是我的代码:

JSch jsch = new JSch();

Session session = null;

try {

    jsch.addIdentity("D:\\TEMP\\key.ppk");

    session = jsch.getSession("tiabscp", "ssiw.support.qvalent.com", 22);
    session.setConfig("StrictHostKeyChecking", "no");
    //session.setPassword("");
    session.connect();
    Channel channel = session.openChannel("sftp");
    System.out.println("Getting connected");
    channel.connect();
    System.out.println("connected successfully");
    ChannelSftp sftpChannel = (ChannelSftp) channel;
    sftpChannel.get("remotefile.txt", "localfile.txt");
    sftpChannel.exit();
    session.disconnect();
}catch (JSchException e) {

    e.printStackTrace();

}catch (SftpException e) {

    e.printStackTrace();
}

请在帖子中包含打印堆栈跟踪。 - Visruth
5个回答

34

我猜测您的密钥不是OpenSSH密钥文件格式。JSch期望私钥采用OpenSSH格式。

您可以使用PuTTYgen按照这里描述的步骤将私钥转换为与OpenSSH兼容:

  1. 点击“Load”并选择用PuTTYgen创建的私钥。
  2. 输入密码以加载密钥。
  3. 从“Conversions”菜单中选择导出OpenSSH密钥
  4. 保存私钥。

非常感谢您的回复。按照您提供的步骤转换为OpenSSH后,我已经能够连接到服务器了。非常感激您的支持。 - Virgo_The_Perfectionist
@rgerganov,JSch可以支持读取SSH2格式的私钥吗? - yapkm01
你救了我的一天!JSch需要OpenSSH密钥文件格式中的私钥。 - user1561521
运行 "openssl rsa -in id_rsa -out id_rsa.decrpt" 命令,然后使用 id_rsa.decrpt 作为私钥即可正常工作。 - Jeryl Cook
1
我认为Java问题不应该只有Windows的答案。 - Rob N
实际上,JSch支持.ppk密钥文件(尽管它可能在使用某些特定版本的PuTTYgen生成的密钥时存在问题)。 - Martin Prikryl

5

也许这不是你的解决方案,但我在搜索我的问题时发现了这个问题。

当JSCH期望私钥文件时,我错误地给出了公钥文件的路径。


一个非常相关的观察。这也是我的情况。 - Newton fan 01

1
你可以使用PEMWriter将私钥转换为PEM格式,这样JSch就可以接受它了。
下面的示例将从Java KeyStore (JKS)返回的密钥转换为PEM格式。
Key privateKey = KeyStore.getKey(privateKeyAlias, keyStorePassword);//get key from JKS
StringWriter stringWriter = new StringWriter();
PEMWriter pemWriter = new PEMWriter(stringWriter);
pemWriter.writeObject(privateKey);
pemWriter.close();

byte[] privateKeyPEM = stringWriter.toString().getBytes();

0

我在使用JSch进行ppk到ssh连接时遇到了同样的问题。这个方法可能适用于某些人。

在使用来自Putty的ppk文件时,它可以正常工作。但是在使用JSch时,它会抛出异常。

我尝试了几种解决方案。最终,我只是将ppk文件加载到PuTTYgen中,并保存私钥,生成了一个类似的(在文本编辑器中)文件,但它可以正常工作。

  1. 点击“Load”并选择ppk文件
  2. 输入密码
  3. 点击“Load”选项下方的“Save private key”按钮并保存私钥

0
以下示例代码可能会对你有所帮助。
package ssh.control;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import android.util.Log;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;


public class SSHConnections {
    static String user="";
    static String pass="";
    static String ip="";


    static Session session;

    public static ChannelExec getChannelExec() throws Exception{
        //System.out.println("connected");
        //This class serves as a central configuration point, and as a factory for Session objects configured with these settings.
        JSch jsch = new JSch();
        //A Session represents a connection to a SSH server.
        session = jsch.getSession(user, ip, 22);
        //getSession()   :-  the session to which this channel belongs. 
        session.setPassword(pass);

        // Avoid asking for key confirmation
        //http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Properties.html
        Properties prop = new Properties();
        prop.put("StrictHostKeyChecking", "no");


        //Sets multiple default configuration options at once. 
        session.setConfig(prop);

        session.connect();
        if(session.isConnected()) {
            System.out.println("connected");
        }

        // SSH Channel 
        //Opens a new channel of some type over this connection. 
        ChannelExec channelssh = (ChannelExec) session.openChannel("exec");

        return channelssh;
    }

    public static  String[] executeRemoteCommand(String command) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ChannelExec channelssh = SSHConnections.getChannelExec();
        channelssh.setOutputStream(baos);

        // Execute command
        channelssh.setCommand(command);//gedit tt
        InputStreamReader isr = new InputStreamReader(channelssh.getInputStream());

        BufferedReader bufred = new BufferedReader(isr);

        channelssh.connect();
        String s = bufred.readLine();

        List<String> lines = new ArrayList<String>();

        int count = 0;
        while( s!=null ) {
            //System.out.println(s);
            lines.add(count,s);
            //      filesandfolders[count]=s;
            //      System.out.println(filesandfolders[count]);
            s = bufred.readLine();  
            count++;
        }

        String filesandfolders[] = new String[count];

        for(int i = 0; i<count;i++) {
            filesandfolders[i] = lines.get(i);
            Log.d("filesandfolders[i]", filesandfolders[i]);
        }
        //for(int j=0;j<filesandfolders.length;j++) {
        //System.out.println(filesandfolders[j]);
        //}
        //System.out.println("lines is "+lines.get(0));
        //int a;
        //while((a = isr.read()) != -1)
        //System.out.print((char)a);
        //channelssh.disconnect();
        //return baos.toString();
        return filesandfolders;
    }

    public static  List<String> executeRemoteCommand1(String command) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ChannelExec channelssh=SSHConnections.getChannelExec();
        channelssh.setOutputStream(baos);

        // Execute command
        channelssh.setCommand(command);//gedit tt
        InputStreamReader isr = new InputStreamReader(channelssh.getInputStream());

        BufferedReader bufred = new BufferedReader(isr);

        channelssh.connect();
        String s = bufred.readLine();

        List<String> lines = new ArrayList<String>();

        int count=0;
        while(s != null) {
            //System.out.println(s);
            lines.add(count, s);
            //      filesandfolders[count] = s;
            //      System.out.println(filesandfolders[count]);
            s = bufred.readLine();  
            count++;
        }

        String filesandfolders[] = new String[count];

        for(int i=0; i<count;i++) {
            filesandfolders[i]=lines.get(i);
        }
        //for(int j=0;j<filesandfolders.length;j++) {
        //System.out.println(filesandfolders[j]);
        //}
        //System.out.println("lines is "+lines.get(0));
        //int a;
        //while((a = isr.read()) != -1)
        //System.out.print((char)a);
        //channelssh.disconnect();
        //return baos.toString();
        return lines;
    }
}

创建一个目录的方法如下:

SSHConnections.user = "username";
SSHConnections.ip = "192.168.1.102";
SSHConnections.pass = "mypassword";
ChannelExec channelssh = SSHConnections.getChannelExec();

String dirname = "sampledirectory";
try {
    String[] str = SSHConnections.executeRemoteCommand("mkdir "+dirname);
} catch (Exception e) {
    e.printStackTrace();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接