技術ブログを開設しました。

Android KeyStoreの概要

こんにちは。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などの詳細も気になるところですが、今回はここまでです。