Kotlinプロジェクトでどこまでキーを隠蔽化できるか（その2：C++の利用）

[前回の記事](https://qiita.com/goofmint/items/beb81edbefd252de9ba2)では単純にAPKファイルを作成し、その中からアプリケーションキーやクライアントキーが見つけられるのを確認しました。今回から、その隠蔽方法について解説していきます。

まず初回は（といっても一番正解に思えます）C++を使って隠蔽する方法です。

## Androidプロジェクトを作る

C++に対応するため、Androidプロジェクトを作成する際にNative C++を選択します。

![ScreenShot_ 2021-11-04 18.17.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/db7ec83c-8b27-a87c-e1aa-f5296136c359.png)


言語はKotlinで問題ありません。

![ScreenShot_ 2021-11-04 18.18.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/782fbe04-e27a-8042-85af-be26ef822519.png)


## native-lib.cppの編集

`app/cpp` ディレクトリにnative-lib.cppというファイルがありますので、これを編集します。

![ScreenShot_ 2021-11-05 11.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2ae8d788-62b8-9ed9-230c-585e4742e6d6.png)


今回はアプリケーションキーとクライアントキーを返却する関数を追加します。 `YOUR_APPLICATION_KEY` と `YOUR_CLIENT_KEY` はそれぞれ書き換えてください。

```cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_applicationKey(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "YOUR_APPLICATION_KEY";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_kotlinhiddenkey_MainActivity_clientKey(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "YOUR_CLIENT_KEY";
    return env->NewStringUTF(hello.c_str());
}
```

これで関数の追加が完了です。

## Android SDKを導入する

次にNCMBのAndroid SDKを導入します。これは[イントロダクション (Android) : クイックスタート | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/introduction/quickstart_android.html)に沿って進めてもらえば問題ありません。具体的には次の手順を行います。

1. GitHubのリリースページからSDKをダウンロードして展開
2. NCMB.jarをapp/libsディレクトリに入れる
3. app/build.gradle の編集
4. app/src/main/AndroidManifest.xml の編集

![ScreenShot_ 2021-11-05 11.55.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/b38117d4-afb7-402b-7c72-b02c9ea583fa.png)


## コードを修正する

MainActivity.kt を修正します。まずSDKを読み込みます。

```kotlin
import com.nifcloud.mbaas.core.NCMB;
```

次にC++ファイルで設定した関数を定義します。

```kotlin
class MainActivity : AppCompatActivity() {
  // 省略
  external fun applicationKey(): String
  external fun clientKey(): String
}
```

そしてNCMBの初期化時に呼び出します。

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    NCMB.initialize(this.getApplicationContext(),applicationKey(),clientKey());
    // 省略
}
```

これで完了です。

## 実行する

初期化が終われば、後は普段のNCMB利用と同じく使えます。

```kotlin
// クラスのNCMBObjectを作成
val obj = NCMBObject("TestClass")
// オブジェクトの値を設定
try {
    obj.put("message", "Hello, NCMB!")
} catch (e: NCMBException) {
    e.printStackTrace()
}
// データストアへの登録
obj.saveInBackground { e ->
    if (e != null) {
        //保存に失敗した場合の処理
        Log.d("Main", "Data creates failed.");
    } else {
        //保存に成功した場合の処理
        Log.d("Main", "Data creates successful.");
    }
}
```

## キーについて

jedx-guiを使って見ても、関数を呼んでいるだけです。

![ScreenShot__2021-11-05_12_19_35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2338fd6d-2472-d2b2-abd5-b61b6e508ff5.jpeg)


アプリをビルドしてAPKファイルを作り、それをZipファイルとして展開すると、`libxxxx.so` のようなファイルの存在を確認できます。

![ScreenShot__2021-11-05_12_20_00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/875fd58b-d85a-3626-ddb4-7dae16ccc0c4.jpeg)

これはアーキテクチャごとに作成されます。このファイルはC++の共有ライブラリになります。このファイルを逆コンパイルしてみましたが、アプリケーションキーやクライアントキーとおぼしき部分は見当たりませんでした（反転している部分がapplicationKey関数の該当とおぼしき部分）。

![ScreenShot_ 2021-11-05 12.38.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/cec7f911-91d0-ba08-712c-1ad8cf164da5.png)

### HEXエディタを使った場合

今回は単純な文字列を返すだけにしたので、HEXエディタで検索するとキーを発見できます。

![ScreenShot__2021-11-05_17_44_47.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/58c3a5db-e49e-c6ae-3bfb-e747e63db8c6.jpeg)

あらかじめキーをエンコードしておいて、C++からデコードして返すようにしたり、文字を分割したりすると発見しづらくなりそうです。

## まとめ

アプリケーションキーやクライアントキーを確実に隠蔽化する場合には、C++プロジェクトとしてAndroidアプリを開発するのが一番かと思います。キーの取得だけをC++の関数としていますので、他のコードはKotlinが使えるので、生産性は変わらないでしょう。お試しください。