如何在 Android Pie 上 运行 Apache-Mina SSHD-Server (2.2.0)?

How to run an Apache-Mina SSHD-Server (2.2.0) on Android Pie?

我正尝试在 Android Pie (API 28.0) 设备上 运行 Apache MINA SSHD 服务器 (v. 2.2.0)。我在 Android 4 台设备上 运行ning 发现了各种 post,但其中 none 似乎可以在我的 Android 9 设备上运行。所以我尝试自己实现它,但在使用 ReflectionException/NoClassDefFoundError.

初始化服务器时卡住了

当我尝试使用 SshServer.setUpDefaultServer() 设置服务器时;我得到这个例外:

java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/management/ReflectionException;
        at org.apache.sshd.common.util.GenericUtils.peelException(GenericUtils.java:730)
        at org.apache.sshd.common.util.GenericUtils.peelException(GenericUtils.java:728)
        at org.apache.sshd.common.util.security.SecurityEntityFactory.getInstance(SecurityEntityFactory.java:134)
        at org.apache.sshd.common.util.security.SecurityUtils.getMessageDigest(SecurityUtils.java:726)
        at org.apache.sshd.common.digest.DigestUtils.checkSupported(DigestUtils.java:53)
        at org.apache.sshd.common.digest.BuiltinDigests.<init>(BuiltinDigests.java:61)
        at org.apache.sshd.common.digest.BuiltinDigests.<clinit>(BuiltinDigests.java:36)
        at org.apache.sshd.common.cipher.ECCurves.<clinit>(ECCurves.java:61)
        at org.apache.sshd.common.keyprovider.KeyPairProvider.<clinit>(KeyPairProvider.java:63)
        at org.apache.sshd.common.signature.BuiltinSignatures.<clinit>(BuiltinSignatures.java:62)
        at org.apache.sshd.common.BaseBuilder.<clinit>(BaseBuilder.java:133)
        at org.apache.sshd.server.ServerBuilder.builder(ServerBuilder.java:165)
        at org.apache.sshd.server.SshServer.setUpDefaultServer(SshServer.java:429)
        at ch.zhaw.init.sshshell.SshShellService.<init>(SshShellService.java:20)

从一些较旧的 posts for Android 4 看来,这是一个已知问题,解决方案是将 $useLibrary 'org.apache.http.legacy' 添加到 gradle并添加到 manifest.xml。我这样做了,但仍然出现异常。

build.gradle 文件:

android {
    compileSdkVersion 28
    useLibrary 'org.apache.http.legacy'
    ...
}
dependencies {
    ...
    implementation 'org.apache.sshd:sshd-core:2.2.0'
    implementation 'org.slf4j:slf4j-simple:1.6.2'
    implementation 'org.apache.mina:mina-core:2.1.2'
    implementation "org.bouncycastle:bcprov-jdk16:1.46"
}

manifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="ch.zhaw.init.sshshell">
    <application
            android:networkSecurityConfig="@xml/network_security_config">
        <uses-library android:name="org.apache.http.legacy"
                      android:required="false" />
        <service android:name=".SshShellService">
            <intent-filter>
                <action android:name="StartSshServer"/>
            </intent-filter>
        </service>
    </application>
</manifest>

我的Java-代码:

import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;


private static final int PORT = 8022;
private final SshServer sshd = SshServer.setUpDefaultServer(); // Here I get the error
private final SimplePasswordAuthenticator passwordAuth = new SimplePasswordAuthenticator();
private final SimplePublicKeyAuthenticator publicKeyAuth = new SimplePublicKeyAuthenticator();
private final SimpleForwardingFilter forwardingFilter = new SimpleForwardingFilter();

似乎旧版本可以工作,但我搜索了几天,但没有找到任何最新版本的工作示例。有没有人有一个工作示例,其中 运行 是 Android 9 上最新版本的 Apache Mina SSHD (2.2.0)(无需对设备进行 root)?

或者如果没有,是否有用于 Android Pie 的替代 SSH 服务器(不是客户端 - 有很多)?

感谢您的帮助。

对于这个特定的失败,创建一个虚拟的 ReflectionException class (example) 就足够了。鉴于 class 甚至不存在,您自己的代码之外的任何东西都不会实例化它,因此 SSHD 的 instanceof ReflectionException 检查永远不会匹配,您不需要对其任何成员进行编程。

您还需要创建一个虚拟 MBeanException (example)

由于 BouncyCastle 库导致的错误已被弃用为 android9(api 级别 28)。

您可以从 aosp 获取详细提示:http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/sun/security/jca/Providers.java#548

https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html

要解决这个问题,您可以按照以下步骤操作:

  1. 从系统默认卸载 BouncyCastleProvider
Security.removeProvider("BC");
  1. 安装新的“BC”自定义提供程序
Security.addProvider(new BouncyCastleProvider());
  1. 初始化你的 mina sshd 服务
 SshServer sshd = SshServer.setUpDefaultServer();
 sshd.setPort(ssdServerPort);
 ....

aosp 只是比较对象来决定 bc 提供者对象是否是系统默认提供者,所以只需替换为新的 bc 提供者对象 :http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/sun/security/jca/Providers.java#341

注意:您必须使用 :Security.removeProvider("BC") 卸载提供程序,然后再安装提供程序