40
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android Keystoreの概要

Posted at

昨今、システム開発においてセキュリティの重要性は増しています。
Androidのセキュリティ機構としては、Android Keystoreシステムなどが挙げられますね。
このAndroid KeystoreはAndroid developersのサイトに説明があるのですが、日本語だとちょっと読みづらい所があったので、自分なりに概要をまとめてみました。

Android Keystoreシステムとは

ざっくりまとめると、「Androidデバイス内の安全な領域に暗号化キーを保管するための仕組み」と言えそうです。
暗号化キーをアプリ内にそのまま保持したりすると、ルート化された端末だと丸見えになります。
「セキュアなデータを端末内に保持する必要がある」などのセキュリティが重視される要件ではAndroid Keystoreの使用も検討しましょう。

Android Keystoreの特徴

  1. 暗号化キーはデバイスから抽出が困難なコンテナ内に保管される
  2. 特定の暗号化モードでしか暗号化キーを使用できないように設定することができる
  3. 暗号化キーを使用する際にユーザー認証を求めることができる

Android Keystoreはどうやって暗号化キーのキーマテリアル抽出を困難にしているのか

  • キーマテリアル(注1)の使用を「暗号化操作を実行するシステムプロセス」にしか許可しない
  • 「アプリプロセス」にキーマテリアルの使用を許可しない
  • Androidデバイスの安全なハードウェア(Trusted Execution Environment(TEE)、セキュア エレメント(SE)など)にキーマテリアルをバインドできるようにしている

注1… 解釈が曖昧ですが、ここでは「暗号化キー生成の元となるデータ」を指していると思われます。

暗号化キーの作成方法

以下のソースコードは、AndroidKeystoreプロバイダを利用して暗号化キーを作成する手順の一例です。
ここではRSAアルゴリズムの鍵ペアを作成しています。
共通鍵等のその他の鍵の生成方法や、暗号モードの指定方法の詳細はAndroid developersなどを参考にしましょう。
(例外処理は省略)

Android Keystoreインスタンスの取得

AndroidKeyStoreインスタンスの取得
    /*
    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)

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

40
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?