sea314です。
今回はFileSYNCというスマホからPCにファイル転送できるツールを開発した話を書きたいと思います。
目次
- 概要
- 開発動機
- 開発記
- 出来たもの
- 技術的な話
- 感想
概要
任意のファイルをAndroidスマートフォンからWindowsPCにWi-Fiルーター経由で転送できるツールです。スマートフォン上で動作するクライアントアプリ、パソコン上で動作するサーバーアプリケーションで構成されています。
クライアントのAndroidアプリはJava、サーバーのWindowsアプリケーションはサーバー本体はGo、サーバーUIはC++で開発しています。
開発動機
スマートフォンからパソコンにファイルを転送するときに、わざわざUSBで接続したりLINEなどで転送するのが煩わしい。
コロナ禍で大学の講義がオンライン化され、課題の提出方法もWebからの提出になりました。それにより、課題を紙に解いてスマホで写真に撮り、パソコンに転送してからWebで提出という作業が頻発するようになりました。提出の度にUSBで接続したり、LINEなどで転送したりというのは正直かなり面倒でした。
Java、Androidアプリ、Go言語、ネットワーク通信の勉強として役に立つものが作りたい。
当時Javaを使ったことはあまりなく、ネットワーク通信もソケット通信しか経験がなく、AndroidアプリとGo言語に関しては完全に初心者でした。プログラミング言語は実際に使いながら勉強するのが一番良いので、いつか勉強したいと思いつつ放置していたこれらをツール開発で勉強することにしました。
スマートフォン内のデータを定期的にバックアップしたい。
万人が思うであろうバックアップが面倒くさい問題。実はこれを作り始める数日前、友人が釣り堀にスマホを落としてしまいデータまるごと全ロストする事件がありました。自分もスマホの中身を定期的にバックアップしなければと感じたものの、Android標準機能のバックアップはGoogleドライブは容量が一杯で保存できず、定期的にUSB接続でPCに転送も忘れるしそもそも面倒くさい。そこで定期的にPCに自動バックアップしてくれるツールを作れば良いという発想に至りました。
開発記
6/6 開発開始
6/9 HTTPを使ってファイルを転送する機能を作りました。サーバーの探索が無いので、IPアドレス直指定です。クライアントはファイルを選択して読み込みサーバーに転送、サーバーは送られてきたファイルを保存という処理です。HTTPを初めて使いましたが、思った以上に簡単に作れて驚きました。TCPソケット直で触るより楽でした。
6/12 サーバーを探索する機能を作りました。クライアントはブロードキャストを送信して、サーバーはそれを受信したら返事をします。ブロードキャストというのはエリア内の全ての端末宛に送れる特殊なメッセージです。個人的には実現できるか不安な箇所だったので、うまく動作して安心しました。
6/13 認証を追加しました。認証には乱数+パスワードから生成したハッシュ値を使います。ハッシュ値はハッシュ関数の出力値です。ハッシュ関数は入力を復号出来ない形で暗号化する関数で、入力が同一なら出力も同一、入力が異なれば出力も異なり、出力から入力が推測困難であるという特徴があります。この性質を利用すると、クライアントは乱数と乱数+パスワードから生成したハッシュ値だけ送信して、サーバーでもハッシュ値を計算して受信したハッシュ値と一致したかどうか確かめることができ、一致すればクライアントが本物であると確認できます。自分で考えた方法でしたが、調べてみたらDigest認証という名前がついていました。残念。
6/17 サーバーUIを作りました。サーバー本体の起動・終了・設定変更を行うためのものです。C++はかなり長く使ってるのですぐ作れるだろうと思っていたのですが、いつの間にかUTF-8に対応し始めていたり、C#などでは当たり前の機能がなかったりと思ったより苦戦しました。
6/27 設定項目をソースコード直書きからサーバーUIから渡すようにしました。環境変数をプログラム内から変更するのは初めてでした。
7月上旬 研究室・講義でちょっと忙しかった。
7/15 クライアントの設定保存とかファイル選択とか追加しました。
7/20 バックアップ機能を実装しました。ファイル転送は既に実装済みなので、サーバーからクライアントにファイルリスト転送とファイル削除だけ追加しています。ファイルリスト同士を比較して、削除・転送・何もしないを決める処理は、リストをファイル名でソートして前から順に比較するだけでいい感じに作れるので、意外と簡単でした。
8月~11月 開発一旦休止
12/7 暗号化のため開発再開
12/8 クライアント側にAES暗号、RSA暗号を扱うためのクラスを作成しました。実はこの時作成したクラスにかなり致命的なミスがいくつか含まれていて、後で何回か書き直す羽目になっています。
12/11 サーバー側にもAES暗号、RSA暗号を扱うためのクラスを作成しました。
1/4 認証とファイル転送を暗号化しました。
1/8 サーバーからクライアントへのファイルリスト転送を暗号化しました。
1/10 ファイル削除を暗号化しました。これで全ての機能が暗号化され、盗聴・改ざん・なりすましが出来ないようになったはずです。
出来たもの
クライアント
サーバー
技術的な話
サーバーの探索・承認
サーバーはLAN内の一般的なパソコンなので電源を切る度にIPアドレスが変化する可能性があります。そのため、クライアントは接続のためにサーバーのアドレスを調べる必要があります。
- クライアントはLAN内の全端末に乱数とハッシュ値Aをブロードキャストで送信します。ハッシュ値Aは乱数とIPアドレスとパスワードから生成しています。
- サーバーは乱数とIPアドレスとパスワードからハッシュ値を計算し、ハッシュ値Aと一致したら送信元をクライアントとして認識します。
- サーバーはクライアントに公開鍵とハッシュ値BをUDPで送信します。ハッシュ値Bはハッシュ値Aと公開鍵とIPアドレスとパスワードから生成しています。
- クライアントは公開鍵とIPアドレスとパスワードとハッシュ値Aからハッシュ値を計算し、ハッシュ値Bと一致したら送信元をサーバーとして認識します。
- クライアントはサーバーに公開鍵を暗号化した共通鍵をHTTPで送信します。
- クライアントとサーバーは共通鍵で暗号化したデータを送受信します。
暗号化
HTTPはデータを暗号化せずに送信するため、第三者が内容の盗聴・改ざん・なりすましが容易です。HTTPのヘッダー、ボディ、レスポンスを共通鍵で暗号化することで盗聴対策とし、内容全体・IPアドレス・パスワードから生成したハッシュ値もつけることで改ざん・なりすまし対策としています。
感想
Wi-Fi経由でファイル共有するツールが欲しくて作り始めたんですが、実はこういうことが出来るツールは既にあるんですよね...
ただ、自分で制作することにより色々カスタマイズできたり、開発過程で勉強になったりしたのでいい経験になりました。