こんにちは。G・B・S 第2システム開発部の小路です。
昨今、システム開発においてセキュリティの重要性は増しています。
Androidのセキュリティ機構としては、Android Keystoreシステムなどが挙げられますね。
このAndroid KeystoreはAndroid developersのサイトに説明があるのですが、日本語だとちょっと読みづらい所があったので、自分なりに概要をまとめてみました。
Android Keystoreシステムとは
ざっくりまとめると、「Androidデバイス内の安全な領域に暗号化キーを保管するための仕組み」と言えそうです。
暗号化キーをアプリ内にそのまま保持したりすると、ルート化された端末だと丸見えになります。
「セキュアなデータを端末内に保持する必要がある」などのセキュリティが重視される要件ではAndroid Keystoreの使用も検討しましょう。
Android Keystoreの特徴
- 暗号化キーはデバイスから抽出が困難なコンテナ内に保管される
- 特定の暗号化モードでしか暗号化キーを使用できないように設定することができる
- 暗号化キーを使用する際にユーザー認証を求めることができる
Android Keystoreはどうやって暗号化キーのキーマテリアル抽出を困難にしているのか
- キーマテリアル(注1)の使用を「暗号化操作を実行するシステムプロセス」にしか許可しない
- 「アプリプロセス」にキーマテリアルの使用を許可しない
- Androidデバイスの安全なハードウェア(Trusted Execution Environment(TEE)、セキュア エレメント(SE)など)にキーマテリアルをバインドできるようにしている
注1… 解釈が曖昧ですが、ここでは「暗号化キー生成の元となるデータ」を指していると思われます。
暗号化キーの作成方法
以下のソースコードは、AndroidKeystoreプロバイダを利用して暗号化キーを作成する手順の一例です。
ここではRSAアルゴリズムの鍵ペアを作成しています。
共通鍵等のその他の鍵の生成方法や、暗号モードの指定方法の詳細はAndroid developersなどを参考にしましょう。
(例外処理は省略)
Android Keystoreインスタンスの取得
/* Keystore.getInstanceの引数に"AndroidKeyStore"を指定し、Android KeyStoreのインスタンスを取得する。 このインスタンスはフィールドにAndroidKeyStoreSpiのインスタンスを保持する。 */ val keyStore: KeyStore = KeyStore.getInstance("AndroidKeyStore") //Android KeyStoreをロードする。内部のAndroidKeystoreSpiがこのメソッドにより初期化されるため、この処理が必要 keyStore.load(null)
鍵ペアの生成
/* 鍵ペアを作成するためのKeyPairGeneratorのインスタンスを取得する 引数のproviderに"AndroidKeyStore"を指定することで、 Android Keystoreに鍵ペアを作成するKeyPairGeneratorSpiインスタンスを取得する */ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore" ) // 作成する鍵ペアのスペックを指定するためのKeyGenParameterSpecインスタンスを生成 val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( "hoge", //エイリアスを"hoge"に設定。Android KeyStoreからエントリーを取得する際はこのエイリアスを使用する。 KeyProperties.PURPOSE_SIGN//鍵の使用目的を指定する。ここでは署名のみを目的とした鍵を生成。指定した目的以外で鍵を使用するとInvalidKeyExceptionが発生する ).run { //使用するダイジェストのアルゴリズムをSHA-256に限定する。これ以外のダイジェストアルゴリズムの使用は拒否される。 setDigests(KeyProperties.DIGEST_SHA256) //使用するパディングモードの指定。RSA鍵ペアを生成する場合は指定必須。指定したパディングモード以外は拒否される。 setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) build() } //指定したKeyGenParameterSpecでKeyPairGeneratorを初期化 kpg.initialize(parameterSpec) //KeyPairGeneratorで鍵ペアを生成 val kp = kpg.generateKeyPair()
データへの署名処理
//署名対象のデータ val str = "sign" val data = str.toByteArray(StandardCharsets.UTF_8)</h4> // Android KeyStoreのインスタンスを取得 val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } //Android KeyStoreからエイリアスを指定してKeystoreエントリを取得する val entry = keyStore.getEntry("hoge", null) //署名を作成/検証するためのSignatureインスタンスを取得。引数は適宜変更必要。 val s = Signature.getInstance("SHA256withRSA") //秘密鍵を指定してSignatureインスタンスを初期化する。ここでは変数entryはprivate keyであること前提 s.initSign((entry as KeyStore.PrivateKeyEntry).privateKey) //Signatureインスタンスによる署名対象データの更新を実行 s.update(data) //署名対象データに署名する val signature = s.sign() //署名したデータをBase64エンコード val result = Base64.encodeToString(signature, Base64.DEFAULT)
Android KeyStoreを利用した暗号化キー生成を実装してみましたが、触ってみると非常に奥が深いですね。TEEやSEなどの詳細も気になるところですが、今回はここまでです。