Unityの暗号ライブラリCryptgraphyを使って通信してみたかったので試してみました。実用性はあまりないかと思います。普通はopensslとか使うだろうし・・・ ※この記事は2021年9月時点のものです。将来UnityまたはJavaScriptの仕様が変わり現在の手法が使えなくなる可能性がありますのでご了承のうえ参考にして下さい。
# 動作確認した環境
# クライアント側
- ・ windows10
- ・ Unity2020.3.17
- ・ VS CODE
# サーバー側(ローカルホスト)
- ・ Docker-compose
- ・ Node.js 14.17.5
# 暗号に関する基本用語解説
用語 | 説明 |
---|---|
暗号化 | データの内容を他人にはわからないようにする事。 |
複合化 | 暗号化されたデータを元の状態に戻す事。 |
AES | 現在最もポピュラーなほぼ世界標準の暗号化規格です。 |
encrypt | 英語で暗号化のこと |
decrypt | 英語で複合化のこと |
ハッシュ | 乱数で作られた暗号化するためのための文字列。厳密には暗号とは違う。 |
sha256 | 現在割とよく用いられているハッシュの規格。今回もこれを使います。 |
iv | initialization vectorの略。暗号を初期化するための乱数の塊のようなもの。 |
salt | 塩じゃないよ!パスワードをハッシュ化するために使われる乱数の塊のようなもの。 |
key | 暗号を解くための鍵である。パスワードとsaltを足したものをsha256などでハッシュ化する事で算出する。 |
# 今回やること
- ・ node.jsで受信データを暗号化、複合化して返すだけの簡素なサーバーを立てる
- ・ Unityエディターからcryptographyを使って暗号化された文字列をサーバーに送信する
- ・ サーバーは暗号化文字列を受け取ったらcrypto-jsを使って一旦複合化する
- ・ それをまたすぐ暗号化して元のクライアントに送信する
- ・ Unity側でサーバーからの返信を受け取り複合化する。そしてログを表示する。
# Node.jsサーバを立ち上げる
# Node.jsの入手
# Javascriptファイルを用意する
暗号化にはcrypto-jsモジュールを使います。また、クライアントとの通信にはweb-requestではなくソケット通信(net)を使います。 事前にnpm等でインストールしておいて下さい。
下記は簡単なテストプログラムです。 パスワード(Password)をかけた暗号データを受信すると、
受信データ → 複合化 → 暗号化 → クライアントに送信
ただこれだけの簡単なテストです。クライアント側は、送ったデータがそのまま送り返されてくる形にになります。厳密には複合化され再暗号化されてるので全く同一というわけではありませんが・・・
# 初期設定。パラメータ(定数)の設定
port:3000はウェルノウン番号といって、一般に良く使われる番号です。わかり易い半面狙われ易いので公開する場合は変えて下さい。
暗号モードはCBC、パディングはPkcs7で、わりと定番の設定です。特にこだわりが無ければこのままでいいでしょう。
passwordはその名のとおりパスワードです。全角は避け半角のみで特殊な環境依存文字も避けましょう。文字数に制限はありませんが極端に長すぎるとバグるかもしれません。
SALT_SIZEは参考にしたサイトが256にしてたのでそのまま使いました。変える場合はクライアント側と数字を揃えましょう。
# 設定が終わったらnodeサーバを起動してみる
で起動するとすぐに受信待ちになります。終了したい時はCTRL+Cで終了します。
バックグラウンド処理をしたい人はpm2を使って下さい。pm2については本題じゃないので割愛します。
# Unity側の設定
# C#スクリプトファイルをコピーする
Unityエディターのassetsフォルダーに下記の3つのファイルをコピーする Crypt.cs (暗号モジュールCryptographyの機能を簡潔にまとめたもの)
SocketNetwork.cs(ソケット通信するための機能を簡潔にまとめたもの)
CryptTest.cs (テスト用プログラム)
CryptTest.csだけ空オブジェクトにアタッチしてインスペクターの変数設定をサーバー側と合わせましょう。
# いざ実行
# 1 Unity側から送信
インスペクターのtext変数に適当な言葉を入れて、nodeサーバが起動していることを確認してunityエディターの実行ボタンを押してみましょう。
繰り返しになりますが、パスワードはサーバー側のものと合わせましょう。違っていると複合化できません。
# 2 nodeサーバで受信
正しく受信されていればサーバー側の画面に下のような受信ログが表示されます。ログの前半は送信されたデータをjson形式で表示したものです。その下にjsonデータをもとに複合化されたtextが表示されています。
また、実際の通信はバイナリ形式で行われています。下図は実際のクライアント←→サーバ間の通信データ。あえてバイナリのまま表示してみました。サーバ側で受信後にjson形式に変換されます。クライアント側も同様です。
まずサーバ側でバイナリデータを受信してjson形式に展開ます。そしてsalt、iv、passwordを元に複合化します。今回の例では緑色のjsonデータを元に「恥ずかしい言葉」というテキストが複合化されました。
次に暗号化関数で新規にsaltとivを発行してkeyを生成して再び「恥ずかしい言葉」を暗号化します。暗号データはjson形式になり、再びバイナリデータとしてクライアント側に送信されます。
# 3 Unityクライアントで結果を受信
受信したデータは受信した時点ではバイナリ形式でサーバー側同様jsonに展開されてsalt、ivを使ってサーバー側と全く同じプロセスで複合化されます。