connect()时的Android SSHJ异常 - "未找到KeyFactory ECDSA实现"

dod*_*der 6 java ssh android sshj raspberry-pi

我正在尝试从我的Android应用程序打开SSH客户端会话.尝试连接到本地网络上的设备(Raspberry Pi).我正在使用SSHJ库版本0.10.0.它在ssh.connect()通话中失败,TransportException最终由a引起NoSuchAlgorithmException.请参阅下面的例外树.

SSHClient ssh = new SSHClient(new AndroidConfig());
Session session = null;

try {    
    //ssh.loadKnownHosts();

    // Exception thrown on this line
    ssh.connect("192.168.1.109", 22);

    // Doesn't reach below
    ssh.authPassword("user", "password");
    session = ssh.startSession();
}
catch (net.schmizz.sshj.transport.TransportException ex) {
    ;
}
Run Code Online (Sandbox Code Playgroud)

例外树:

net.schmizz.sshj.transport.TransportException
 net.schmizz.sshj.common.SSHException
  net.schmizz.sshj.common.SSHRuntimeException
   java.security.GeneralSecurityException: java.security.NoSuchAlgorithmException: KeyFactory ECDSA implementation not found
    java.security.NoSuchAlgorithmException: KeyFactory ECDSA implementation not found
Run Code Online (Sandbox Code Playgroud)

其他系统信息:

SSHJ library   : v0.10.0
Android device : Galaxy Note 3 running Android 4.4.2
Run Code Online (Sandbox Code Playgroud)

我在Android Studio中使用了maven依赖支持来引入SSHJ JAR,除了SSHJ v0.10.0 jar之外,还引入了以下三个库...

bouncy castle...
  bcpkix-jdk15on-1.50.jar
  bcprov-jdk15on-1.50.jar
logging....
  slf4j-api-1.7.7.jar
Run Code Online (Sandbox Code Playgroud)

没有线索从这个例外开始...任何建议表示赞赏!谢谢.

更新:2014年10月31日

正如LeeDavidPainter所建议的那样,我加入了SpongyCastle 1.51.0 JAR并在顶部添加了这一行:

Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
Run Code Online (Sandbox Code Playgroud)

我现在在同一行上得到一个不同的例外:

net.schmizz.sshj.transport.TransportException
 net.schmizz.sshj.common.SSHException
  net.schmizz.sshj.common.SSHRuntimeException
   java.security.GeneralSecurityException: java.security.spec.InvalidKeySpecException: key spec not recognised
    java.security.spec.InvalidKeySpecException: key spec not recognised
Run Code Online (Sandbox Code Playgroud)

还要注意我也尝试了以下行,结果相同:

Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
Run Code Online (Sandbox Code Playgroud)

我的手机上还有另一个应用程序,它基本上完全符合我的要求 - 它叫做RaspberryPiController - 它通过SSH用户名和密码auth连接到你的RPi.这工作正常,所以它似乎不是一个网络问题.

小智 5

Android随附缩小版本的BouncyCastle,其中不包含ECDSA算法。因此,即使您在类路径中包含完整版本,也将选择并使用Android运行时版本。

您可能需要查看http://rtyley.github.io/spongycastle/来解决此问题,它是Bouncycastle的重新打包版本,可以作为Android中的单独JCE提供程序安装。在尝试与SSHJ连接(未试用)之前,只需将其安装为默认的JCE提供程序即可。

Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
Run Code Online (Sandbox Code Playgroud)


dod*_*der 0

在 SSHJ 中无法解决此问题,因此决定尝试一下提供相同功能的JSch 。它也可作为 Maven 存储库使用 - 我使用jsch 版本 0.1.51 ('com.jcraft:jsch:0.1.51')。

它第一次使用此代码片段;

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

import java.io.ByteArrayOutputStream;
import java.util.Properties;

JSch jsch = new JSch();
com.jcraft.jsch.Session session = null;
String result = "";

try {    
  session = jsch.getSession("user", "192.168.1.109", 22);
  session.setPassword("password");

  // Avoid asking for key confirmation
  Properties prop = new Properties();
  prop.put("StrictHostKeyChecking", "no");
  session.setConfig(prop);
  session.connect();

  // SSH Channel
  ChannelExec channel = (ChannelExec)session.openChannel("exec");
  ByteArrayOutputStream stream = new ByteArrayOutputStream();
  channel.setOutputStream(stream);

  // Execute command
  channel.setCommand("ls -ltr");
  channel.connect(1000);
  java.lang.Thread.sleep(500);   // this kludge seemed to be required.
  channel.disconnect();

  result = stream.toString();
}
catch (JSchException ex) {
  String s = ex.toString();
  System.out.println(s);
}
catch (InterruptedException ex) {
  String s = ex.toString();
  System.out.println(s);
}
finally {
  if (session != null)
    session.disconnect();
}
Run Code Online (Sandbox Code Playgroud)

与 SSHJ 相比,使用它时感觉像是一个更强大的实现 - 或者这种印象可能是由于他们选择了相当保守的超时而造成的。例如,如果目标设备已关闭,默认情况下,session.connect() 调用将在放弃之前继续尝试连接大约 20 秒。