我有这个简单的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();
上):
INFO: Connecting to <redacted> port 22 INFO: Connection established INFO: Remote version string: SSH-2.0-OpenSSH_5.1p1 Debian-5 INFO: Local version string: SSH-2.0-JSCH-0.1.42 INFO: CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256 INFO: arcfour is not available. INFO: arcfour128 is not available. INFO: arcfour256 is not available. INFO: SSH_MSG_KEXINIT sent INFO: SSH_MSG_KEXINIT received INFO: kex: server->client aes128-ctr hmac-md5 none INFO: kex: client->server aes128-ctr hmac-md5 none INFO: SSH_MSG_KEXDH_INIT sent INFO: expecting SSH_MSG_KEXDH_REPLY INFO: ssh_rsa_verify: signature true INFO: Host '<redacted>' is known and mathces the RSA host key INFO: SSH_MSG_NEWKEYS sent INFO: SSH_MSG_NEWKEYS received INFO: SSH_MSG_SERVICE_REQUEST sent INFO: SSH_MSG_SERVICE_ACCEPT received INFO: Authentications that can continue: publickey,keyboard-interactive,password INFO: Next authentication method: publickey INFO: Authentications that can continue: password INFO: Next authentication method: password INFO: Disconnecting from <redacted> port 22 com.jcraft.jsch.JSchException: Auth fail at com.jcraft.jsch.Session.connect(Session.java:452) at TestJsch.main(TestJsch.java:19)
当我使用Java 1.7运行相同的程序时,它说
INFO: Connecting to <redacted> port 22 INFO: Connection established INFO: Remote version string: SSH-2.0-OpenSSH_5.1p1 Debian-5 INFO: Local version string: SSH-2.0-JSCH-0.1.42 INFO: CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256 INFO: SSH_MSG_KEXINIT sent INFO: SSH_MSG_KEXINIT received INFO: kex: server->client aes128-ctr hmac-md5 none INFO: kex: client->server aes128-ctr hmac-md5 none INFO: SSH_MSG_KEXDH_INIT sent INFO: expecting SSH_MSG_KEXDH_REPLY INFO: ssh_rsa_verify: signature true INFO: Host '<redacted>' is known and mathces the RSA host key INFO: SSH_MSG_NEWKEYS sent INFO: SSH_MSG_NEWKEYS received INFO: SSH_MSG_SERVICE_REQUEST sent INFO: SSH_MSG_SERVICE_ACCEPT receivedINFO: Authentications that can continue: publickey,keyboard-interactive,password INFO: Next authentication method: publickey INFO: Authentication succeeded (publickey). Linux <redacted> 2.6.26-2-amd64 #1 SMP Mon Jun 13 16:29:33 UTC 2011 x86_64 <server welcome message follows>
我已经为1.4 VM安装了Java Cryptography Extensions(JCE)。
可能是这个问题的根源是什么?
答案 0 :(得分: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的网站上,现在我不知道它在哪里可以找到。
您可以阅读更多in this article
编辑: 经过一番研究,我发现答案是错误的。
Java 1.4不支持超过2048字节长度BUG 4524097
的RSA密钥答案 1 :(得分:3)
我对jsch的问题一直是权限问题。所以我会做以下事情来消除它们作为问题
无法下载源代码并在调试会话中逐步执行。
答案 2 :(得分:1)
您是否尝试过使用Open SSH密钥? jsch使用Open SSH密钥格式。您可以将现有的转换为Open SSH格式。具体方法如下:使用putty keygen并加载现有密钥。系统可能会提示您输入密码进行解密。之后,单击上面的转换选项,然后选择“导出OpenSSH密钥”。在上面的程序中使用这个新生成的密钥。希望这会有所帮助。
答案 3 :(得分:-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;
}
}
}
答案 4 :(得分:-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);