12

我有这个简单的 Java 程序,它使用Jsch连接到 SFTP 服务器。

在 Java 1.4.2 上连接失败并出现“Auth fail”异常,但在 Java 1.7 上连接完美。

try {
    JSch jsch = new JSch();

    jsch.setKnownHosts(KNOWN_HOSTS_PATH);
    jsch.addIdentity(PRIVATE_KEY_PATH, PASSPHRASE);

    Session session = jsch.getSession(USERNAME, HOSTNAME, 22);
    session.connect(2500);

    Channel channel = session.openChannel("shell");
    channel.setInputStream(System. in );
    channel.setOutputStream(System.out);
    channel.connect();
} catch (Exception e) {
    e.printStackTrace(System.err);
}

我使用的钥匙是ssh-rsa 4096位钥匙。.pub密钥文件与私钥位于同一目录中。

连接记录器时,我在异常之前看到以下消息(发生在channel.connect();):

信息:连接到 <redacted> 端口 22
信息:已建立连接
信息:远程版本字符串:SSH-2.0-OpenSSH_5.1p1 Debian-5
信息:本地版本字符串:SSH-2.0-JSCH-0.1.42
信息:校验密码:aes256-ctr、aes192-ctr、aes128-ctr、aes256-cbc、aes192-cbc、aes128-cbc、3des-ctr、arcfour、arcfour128、arcfour256
信息: arcfour 不可用。
信息:arcfour128 不可用。
信息:arcfour256 不可用。
信息:已发送 SSH_MSG_KEXINIT
信息:已收到 SSH_MSG_KEXINIT
信息:kex:服务器->客户端 aes128-ctr hmac-md5 无
信息:kex:客户端->服务器 aes128-ctr hmac-md5 无
信息:已发送 SSH_MSG_KEXDH_INIT
信息:期待 SSH_MSG_KEXDH_REPLY
信息:ssh_rsa_verify:签名为真
信息:主机 '<redacted>' 是已知的并且计算 RSA 主机密钥
信息:已发送 SSH_MSG_NEWKEYS
信息:收到 SSH_MSG_NEWKEYS
信息:已发送 SSH_MSG_SERVICE_REQUEST
信息:收到 SSH_MSG_SERVICE_ACCEPT
INFO:可以继续的身份验证:publickey、keyboard-interactive、password
INFO:下一个认证方法:publickey
信息:可以继续的身份验证:密码
INFO:下一个身份验证方法:密码
信息:从 <redacted> 端口 22 断开连接
com.jcraft.jsch.JSchException:身份验证失败
        在 com.jcraft.jsch.Session.connect(Session.java:452)
        在 TestJsch.main(TestJsch.java:19)

当我用 Java 1.7 运行相同的程序时,它说

信息:连接到 <redacted> 端口 22
信息:已建立连接
信息:远程版本字符串:SSH-2.0-OpenSSH_5.1p1 Debian-5
信息:本地版本字符串:SSH-2.0-JSCH-0.1.42
信息:校验密码:aes256-ctr、aes192-ctr、aes128-ctr、aes256-cbc、aes192-cbc、aes128-cbc、3des-ctr、arcfour、arcfour128、arcfour256
信息:已发送 SSH_MSG_KEXINIT
信息:已收到 SSH_MSG_KEXINIT
信息:kex:服务器->客户端 aes128-ctr hmac-md5 无
信息:kex:客户端->服务器 aes128-ctr hmac-md5 无
信息:已发送 SSH_MSG_KEXDH_INIT
信息:期待 SSH_MSG_KEXDH_REPLY
信息:ssh_rsa_verify:签名为真
信息:主机 '<redacted>' 是已知的并且计算 RSA 主机密钥
信息:已发送 SSH_MSG_NEWKEYS
信息:收到 SSH_MSG_NEWKEYS
信息:已发送 SSH_MSG_SERVICE_REQUEST
INFO: SSH_MSG_SERVICE_ACCEPT receivedINFO: 可以继续的身份验证:publickey,keyboard-interactive,password
INFO:下一个认证方法:publickey
信息:身份验证成功(公钥)。
Linux <redacted> 2.6.26-2-amd64 #1 SMP Mon Jun 13 16:29:33 UTC 2011 x86_64

<服务器欢迎消息如下>

我已经为 1.4 VM 安装了 Java Cryptography Extensions (JCE)。

这个问题的根源可能是什么?

4

5 回答 5

4

Java 在使用强加密算法方面存在限制。检查$JRE_HOME/lib/security/US_Export_policy.jar和的内容$JRE_HOME/lib/security/local_policy.jar。如果你发现这样的事情:

// File: default_local.policy
// Some countries have import limits on crypto strength.
// This policy file is worldwide importable.
grant {
    permission javax.crypto.CryptoPermission "DES", 64;
    permission javax.crypto.CryptoPermission "DESede", *;
    permission javax.crypto.CryptoPermission "RC2", 128,
                   "javax.crypto.spec.RC2ParameterSpec", 128;
    permission javax.crypto.CryptoPermission "RC4", 128;
    permission javax.crypto.CryptoPermission "RC5", 128,
          "javax.crypto.spec.RC5ParameterSpec", *, 12, *;
    permission javax.crypto.CryptoPermission "RSA", 2048;
    permission javax.crypto.CryptoPermission *, 128;
};

决定是下载并安装 JCE Unlimited Strength Jurisdiction Policy。以前,它位于 Sun 的网站上,现在我不知道在哪里可以找到它。

您可以在本文中阅读更多内容

编辑:经过一番研究,我发现我的答案不正确。

Java 1.4 不支持超过 2048 字节长度的 RSA 密钥BUG 4524097

于 2012-08-31T13:17:30.833 回答
3

我对 jsch 的问题与权限有关。所以我会做以下事情来消除它们作为问题

  1. 确保您可以使用生成的密钥在命令行上通过 ssh 连接到远程。
  2. 输入密码并确保您可以连接到遥控器。
  3. 检查本地目录和远程良好 ssh 摘要的权限。
  4. 尝试将本地主机用作远程主机。

未能下载源代码并在调试会话中单步执行。

于 2012-08-20T07:04:42.323 回答
1

您是否尝试过使用 Open SSH 密钥?jsch 使用 Open SSH 密钥格式。您可以将现有的格式转换为 Open SSH 格式。方法如下:使用 putty keygen 并加载您现有的密钥。系统可能会提示您输入密码以进行解密。之后单击上面的转换选项并选择“导出 OpenSSH 密钥”。在上面的程序中使用这个新生成的密钥。希望这可以帮助。

于 2012-07-20T21:25:02.227 回答
-2

此代码工作正常...

public class Exec2 {

static String SSH_SERVER_PATH = "localhost";
static String SSH_SERVER_USERNAME = "root";
static String SSH_SERVER_PASSWORD = "root";

public static void main(String[] arg) {
    try {
        JSch jsch = new JSch();
        String host = SSH_SERVER_PATH;
        String user = SSH_SERVER_USERNAME;

        Session session = jsch.getSession(user, host, 22);

        // username and password will be given via UserInfo interface.

        UserInfo ui = new MyUserInfo();
        session.setUserInfo(ui);
        session.connect();

        String command = "uname";

        Channel channel = session.openChannel("exec");
        ((ChannelExec) channel).setCommand(command);

        channel.setInputStream(null);

        ((ChannelExec) channel).setErrStream(System.err);

        InputStream in = channel.getInputStream();

        channel.connect();

        byte[] tmp = new byte[1024];
        while (true) {
            while (in.available() > 0) {
                int i = in.read(tmp, 0, 1024);
                if (i < 0)
                    break;
                System.out.print(new String(tmp, 0, i));
            }
            if (channel.isClosed()) {
                System.out.println("exit-status: " + channel.getExitStatus());
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee) {
            }
        }
        channel.disconnect();
        session.disconnect();
    } catch (Exception e) {
        System.out.println(e);
    }
}

public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {

    String passwd;

    public String getPassword() {
        return passwd;
    }

    public boolean promptYesNo(String str) {
        return true;
    }


    public String getPassphrase() {
        return null;
    }

    public boolean promptPassphrase(String message) {
        return true;
    }

    public boolean promptPassword(String message) {
        passwd = SSH_SERVER_PASSWORD;
        return true;
    }

    public void showMessage(String message) {
        System.out.println("message = " + message);
    }

    public String[] promptKeyboardInteractive(String destination,
            String name, String instruction, String[] prompt, boolean[] echo) {
        if (prompt[0].equals("Password: ")){
            String[] response = new String[1];
            response[0] = SSH_SERVER_PASSWORD;
            return response;
        }
        return null;
    }
}
}
于 2013-01-11T16:41:27.003 回答
-3

public String getPassphrase() { return null; }

public boolean promptPassphrase(String message) {
    return true;
}

public boolean promptPassword(String message) {
    passwd = SSH_SERVER_PASSWORD;
    return true;
}

public void showMessage(String message) {
    System.out.println("message = " + message);
于 2014-02-04T16:05:28.563 回答