【Kotlin】Android11でApache MINA SSHDを使う【※未達成】

ここ最近ずっとAndroid OSでSSHサーバを起動させるべく、Apache MINA SSHDと格闘していたのですが、あまりにも本当にものすごくウルトラスーパーぶち苦労しているので、少しでも分かったことや確証が取れたことを記録したいと思います。

なおタイトルにもある通り、Android内にSSHサーバを立てて、通信することは未達成です。
中途半端で申し訳ない反面、AndroidでApache MINA SSHDを使っているコードが全然見つからないこと、ましてやKotlinで書かれてたコードなんて皆無だったことから、とりあえずビルドが通って接続はできたというコードだけでも残しておきたかったという事情があります。将来の自分が再び取り組むことになった時、世界の誰かが同じような状況に陥った時、少しでも役に立てば幸いです。
あわよくば完成させてください……

コードはこちら。例によって変更・追加した部分のコードのみ上げています。

環境

・Android Studio Flamingo | 2022.2.1 Patch2
・Kotlin version: 1.8.20
・minSdk 24, targetSdk 33
・Apache MINA SSHD 2.10.0

試した実機(Androidスマホ)
・Xperia 5ⅱ
・Android 11

Apache MINA SSHDを読み込む

そもそもApache MINA SSHDは何なのという話ですが、SSHサーバとSSHクライアントを提供するJavaライブラリです。sshdが入ってなくてもSSHサーバを動かせます。公式

いくつかバージョンがあるのですが、最新を使用します。
これを書いてる現在(2023.7.30)の最新バージョンは、2.10.0です。
Latest SSHD Releaseから該当のバージョンを選択し、SourceかBinaryを選んでダウンロード。今回はBinaryの.zipをダウンロードして、解凍。
その中にあるlibsフォルダとdependenciesフォルダを、Androidプロジェクトのlibsフォルダに入れます。

build.gradle(Module :app)ファイルのdependenciesに、以下を追記してjarファイルを読み込みます。

なお、これだけではまだちゃんと読み込めないので、以下を同ファイルのandroidの部分に追加します。

Sync Nowを押して更新したら準備完了。

SSHサーバの処理

SSHサーバを起動する処理を行うクラスを作成します。
File > New > Kotlin Class/File から Objectを選択し、シングルトンのSshServerクラスを作ります。

まず先にコード全体を載せます。

これをメインアクティビティから呼んでやって完了。

以下、各種説明や発生したエラーについてです。

25行目。

ユーザのホームディレクトリをセットしています。
この記述がないと、以下のようなエラーが発生しました。

エラー内容的には、『ユーザのホームディレクトリが初期化されていない』といったところでしょうか。

27, 28行目。

こちらは、公式ドキュメントのAndroid.mdのSecurity provider(s)のところに言及があります。

The SSHD code uses Bouncycastle if it detects it – however, on Android this can cause some issues – especially if the user’s code also contains the BC libraries. It is not clear how to use it – especially since some articles suggest that BC is bundled into Android or has been so and now it is deprecated. Several Stackoverflow posts suggest that an explicit management is required 

Android support

AndroidでBouncyCastleの使用するのにトラブルがあるらしく、明示的な管理が必要とのこと。
この記述がない場合は、以下のようなエラーが発生しました。

29, 30行目。
インスタンスの立ち上げとポートの設定を行っています。
Androidはルート化しないとウェルノウンポートが使用できないため、一般的なSSHのポートである22は使えません。

32行目。
SSHサーバの鍵の準備。

ここで使用しているBouncyCastleGeneratorHostKeyProviderはプログラム実行時に鍵ペアを生成してくれますが、アプリを起動するたびに鍵が生成されて変わってしまいます。
そのため、アプリ再起動後にクライアントが再び接続しようとすると、前回とサーバの鍵が異なっているためエラーになります。sshコマンドで接続しようとした場合は、『WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!』とかって警告されます。
既存の鍵を使う方法はまだちょっと分かりません……。とはいえ今のままだと毎回鍵が変わっちゃって使えたもんじゃないのでどうにかしないといけないのですが。

ちなみに鍵がちゃんと準備できてない場合は、クライアント側では getKexProposal() no resolved signatures available みたいな表示が出て切断されます。サーバ側では、以下のようなエラーになってます。

34~37行目。
パスワード認証を行います。
今回は認証処理を行っていないため、どんなユーザ名とパスワードでも認証されます。
ちゃんと処理をする場合は入力を受け取って、比較して、間違っていたらfalse、あっていればtrueを返す処理を書く必要があります。パスワード認証をそもそも使うか?って話もあるけど

39, 40行目。と、SshServerStartTaskクラス。

Androidは、通信関連の処理をメインスレッドで行えないため、別スレッドにしてサーバを起動(server.start())しています。

とりあえずこれでアプリは起動するし、sshコマンドで接続しにいくことは可能です。

ただし今回アプリを実行して、PCからスマホにSSH接続しようとしたところ、パスワードを入力して認証が通った後にシェルのエラーになりました。

shellFactoryでいろいろ設定すれば良さそうというところまでは判明しているのですが、何をどう設定するかがまだ不明です。

まだまだ修正が必要な箇所が多いので、今後なにか分かれば追記するか、別途記事にしようと思います。早く解決して解放されたいです。

参考サイト

Embedding an SSHD server instance in 5 minutes at master · apache/mina-sshd

Apache MINA SSHD を使って Java で SFTP サーバをつくる - Qiita
MINA SSHD を使えば Java のプロセスを立ち上げるだけで SFTP サーバが用意できます。 急に SFTP サーバが必要になった時に便利。 Spri...

コメント

タイトルとURLをコピーしました