このページには、Android 6.0 以上のキーストアの暗号機能に関する情報を掲載しています。
暗号プリミティブ
キーストアのオペレーションには、次のカテゴリがあります。
- 鍵の生成
- 非対称鍵のインポートとエクスポート(鍵のラッピングなし)
- 未処理の対称鍵のインポート(鍵のラッピングなし)
- 適切なパディング モードを使用した非対称暗号化および復号
- ダイジェスト モードと適切なパディング モードを使用した非対称署名および検証
- AEAD モードなどの適切なモードでの対称暗号化および復号
- 対称メッセージ認証コードの生成と検証
目的、モード、パディングなどのプロトコル要素、およびアクセス制御の制約は、鍵の生成またはインポート時に指定され、鍵に恒久的にバインドされて、他の方法で鍵を使用できないことを保証します。
上記に加えて、Keymaster 実装が提供するサービスはもう 1 つありますが、API としては公開されていません。それは、乱数の生成です。このサービスは、鍵、初期化ベクトル(IV)、ランダム パディング、およびランダム化を必要とするセキュア プロトコルのその他の要素を生成するために、内部的に使用されます。
必須のプリミティブ
すべての Keymaster 実装は、次の機能を提供します。
- RSA
- 2048、3072、4096 ビット鍵のサポート
- 公開指数 F4(2^16+1)のサポート
- RSA 署名用のパディング モード:
- RSASSA-PSS(
PaddingMode::RSA_PSS
) - RSASSA-PKCS1-v1_5(
PaddingMode::RSA_PKCS1_1_5_SIGN
)
- RSASSA-PSS(
- RSA 署名用のダイジェスト モード:
- SHA-256
- RSA 暗号化 / 復号用のパディング モード:
- パディングなし
- RSAES-OAEP(
PaddingMode::RSA_OAEP
) - RSAES-PKCS1-v1_5(
PaddingMode::RSA_PKCS1_1_5_ENCRYPT
)
- ECDSA
- NIST の P-224、P-256、P-384、P-521 曲線を使用して、それぞれ 224、256、384、521 ビット鍵をサポート
- ECDSA 用のダイジェスト モード:
- ダイジェストなし(サポート終了。将来削除される予定)
- SHA-256
- AES
- 128 および 256 ビット鍵をサポート
- CBC、CTR、ECB、GCM。GCM 実装では、96 ビット未満のタグまたは 96 ビット以外の長さのノンスは使用できません。
- パディング モード
PaddingMode::NONE
およびPaddingMode::PKCS7
は、CBC モードと ECB モードでサポートされます。パディングなしの場合、入力がブロックサイズの倍数でなければ、CBC モードまたは ECB モードの暗号化は失敗します。
- HMAC SHA-256(鍵のサイズは最小 32 バイトまで)
Keymaster 実装では、SHA1 と、SHA2 ファミリーの他のメンバー(SHA-224、SHA384、SHA512)の使用を強くおすすめします。ハードウェアの Keymaster 実装でこれらが提供されない場合は、キーストアがソフトウェアで提供します。
他のシステムとの相互運用には、以下のプリミティブの使用も推奨されます。
- RSA 用の小さい鍵サイズ
- RSA 用の任意の公開指数
鍵アクセス制御
デバイスから抽出できないハードウェア ベースの鍵は、(引き出し可能な鍵より安全だとしても)攻撃者が自由に鍵を使用できる場合は十分なセキュリティを提供しません。したがって、キーストアがアクセス制御を適用することが重要です。
アクセス制御は、タグと値のペアの「承認リスト」として定義されます。 承認タグは 32 ビットの整数で、値の型はさまざまです。いくつかのタグは繰り返し可能であり、複数の値を指定できます。タグが繰り返し可能かどうかは、タグのドキュメントで説明されています。鍵の作成時に、呼び出し元は承認リストを指定します。Keymaster 実装の基盤となるキーストアは、リストを変更して、鍵にロールバック保護があるかなどの追加情報を指定し、返される鍵 blob にエンコード済みの「最終版」承認リストを返します。最終版の承認リストが変更された場合、暗号オペレーションに鍵を使用しようとすると失敗します。
Keymaster 2 以前では、可能なタグのセットは列挙型の keymaster_authorization_tag_t
で定義され、恒久的に固定されています(拡張することは可能です)。
タグの名前には KM_TAG
プレフィックスが付きます。タグ ID の上位 4 ビットは、型を示すために使用されます。
Keymaster 3 では、KM_TAG
プレフィックスが Tag::
に変更されました。
以下の型があります。
ENUM
: 多くのタグの値は列挙型で定義されます。たとえば、TAG::PURPOSE
の可能な値は列挙型の keymaster_purpose_t
で定義されます。
ENUM_REP
: ENUM
と同様ですが、承認リストでタグが繰り返し可能である点が異なります。繰り返しは、複数の承認済みの値を表します。たとえば、暗号鍵は KeyPurpose::ENCRYPT
と KeyPurpose::DECRYPT
を持つ可能性があります。
UINT
: 32 ビットの符号なし整数。例: TAG::KEY_SIZE
UINT_REP
: UINT
と同様ですが、承認リストでタグが繰り返し可能である点が異なります。繰り返しは、複数の承認済みの値を表します。
ULONG
: 64 ビットの符号なし整数。例: TAG::RSA_PUBLIC_EXPONENT
ULONG_REP
: ULONG
と同様ですが、承認リストでタグが繰り返し可能である点が異なります。繰り返しは、複数の承認済みの値を表します。
DATE
: 1970 年 1 月 1 日からのミリ秒数で表される日時の値。例: TAG::PRIVKEY_EXPIRE_DATETIME
BOOL
: true または false。BOOL
型のタグは、タグが存在しない場合は false、存在する場合は true と見なされます。例: TAG::ROLLBACK_RESISTANT
BIGNUM
: 任意の長さの整数。ビッグ エンディアンの順序を持つバイト配列として表現されます。例: TAG::RSA_PUBLIC_EXPONENT
BYTES
: バイトのシーケンス。例: TAG::ROOT_OF_TRUST
ハードウェア適用とソフトウェア適用の比較
セキュア ハードウェア実装がすべて同じ機能を持つわけではありません。Keymaster は、さまざまなアプローチをサポートするために、セキュア環境でのアクセス制御の適用と非セキュア環境でのアクセス制御の適用、ハードウェア適用とソフトウェア適用を区別します。
すべての実装は以下を行います。
- すべての承認の(適用ではなく)完全一致の実施。 鍵 blob 内の承認リストは、鍵の生成時に返される承認と、順序を含めて完全に一致します。不一致があると、診断エラーが発生します。
- セマンティック値が適用される承認の宣言。
ハードウェアによって適用される承認を宣言する API メカニズムは、keymaster_key_characteristics_t
構造内にあります。これにより、承認リストは 2 つのサブリスト hw_enforced
および sw_enforced
に分割されます。セキュア ハードウェアは、適用可能な内容に基づいて、それぞれに適切な値を配置する責任を負います。
さらに、キーストアは、セキュア ハードウェアによって承認が適用されるかどうかにかかわらず、すべての承認のソフトウェア ベースの適用を実装します。
たとえば、鍵の有効期限をサポートしていない TrustZone ベースの実装を考えてみましょう。有効期限付きの鍵も作成できるものとします。その鍵の承認リストには、有効期限を指定したタグ TAG::ORIGINATION_EXPIRE_DATETIME
が含まれます。キーストアに鍵特性をリクエストすると、sw_enforced
リスト内にこのタグが見つかるため、セキュア ハードウェアは有効期限の要件を適用しません。ただし、有効期限を過ぎた鍵の使用は、キーストアによって拒否されます。
デバイスが有効期限をサポートするセキュア ハードウェアでアップグレードされると、鍵特性のリクエストにより hw_enforced
リスト内に TAG::ORIGINATION_EXPIRE_DATETIME
が見つかります。キーストアが妨害またはバイパスされても、有効期限を過ぎた鍵の使用は失敗します。
鍵がハードウェア格納型かどうかを判断する方法については、キー構成証明をご覧ください。
暗号メッセージ作成承認
次のタグは、関連する鍵を使用してオペレーションの暗号特性を定義するために使用されます: TAG::ALGORITHM
、TAG::KEY_SIZE
、TAG::BLOCK_MODE
、TAG::PADDING
、TAG::CALLER_NONCE
、TAG::DIGEST
。
TAG::PADDING
、TAG::DIGEST
、PaddingMode::BLOCK_MODE
は繰り返し可能です。これは、複数の値を単一の鍵に関連付けて、使用する値をオペレーション時に指定できることを意味します。
目的
鍵には、鍵の使用方法を定義したタグ TAG::PURPOSE
を含む 1 つ以上の承認エントリとして表現される、目的のセットが関連付けられています。目的は以下のとおりです。
KeyPurpose::ENCRYPT
KeyPurpose::DECRYPT
KeyPurpose::SIGN
KeyPurpose::VERIFY
これらの目的のサブセットを任意の鍵に関連付けることができます。組み合わせによってはセキュリティ問題が発生することにご注意ください。たとえば、暗号化と署名の両方に使用できる RSA 鍵の場合、攻撃者が、任意のデータを復号して署名を生成することをシステムに受け入れさせる危険があります。
インポートとエクスポート
Keymaster は、X.509 形式の公開鍵のエクスポートと、次のインポートをサポートしています。
- DER でエンコードされた PKCS#8 形式の公開鍵と秘密鍵のペアをパスワード ベースの暗号化なしでインポート
- 対称鍵を生のバイトとしてインポート
インポートされた鍵とセキュアに生成された鍵を区別できるようにするため、TAG::ORIGIN
が適切な鍵承認リストに含まれています。たとえば、セキュア ハードウェアで鍵が生成された場合、KeyOrigin::GENERATED
の値を持つ TAG::ORIGIN
が鍵特性の hw_enforced
リスト内に見つかります。一方、セキュア ハードウェアにインポートされた鍵は、KeyOrigin::IMPORTED
の値を持ちます。
ユーザー認証
セキュアな Keymaster 実装はユーザー認証を実装せず、ユーザー認証を実装した他の信頼できるアプリに依存します。そうしたアプリが実装するインターフェースについては、ゲートキーパーのページをご覧ください。
ユーザー認証の要件は、2 つのタグセットで指定します。 1 つ目のセットは、鍵を使用できるユーザーを示します。
TAG::ALL_USERS
は、鍵がすべてのユーザーによって使用可能であることを示します。このタグが存在する場合、TAG::USER_ID
とTAG::USER_SECURE_ID
は存在しません。TAG::USER_ID
は、承認済みユーザーの ID を指定する数値です。これはアプリの UID ではなく Android ユーザー ID(マルチユーザー向け)であり、非セキュア ソフトウェアによってのみ適用されることにご注意ください。このタグが存在する場合、TAG::ALL_USERS
は存在しません。TAG::USER_SECURE_ID
は、鍵の使用をロック解除するためにセキュア認証トークンで提供されるセキュア ユーザー ID を指定する 64 ビットの数値です。タグが繰り返されている場合、セキュア認証トークンでいずれかの値が提供されていれば、鍵を使用できます。
2 つ目のセットは、ユーザーを認証する必要があるか、あるとすればいつ必要かを示します。以下のタグがどれも存在せず、TAG::USER_SECURE_ID
が存在する場合は、鍵を使用するたびに認証が要求されます。
NO_AUTHENTICATION_REQUIRED
はユーザー認証が不要であることを示します。ただし、鍵は引き続きTAG::USER_ID
で指定されたユーザーとして実行されているアプリでのみ使用できます。TAG::AUTH_TIMEOUT
は、ユーザー認証が鍵の使用を承認する際のタイムアウト期間を秒数で指定する数値です。これは、秘密鍵 / シークレット鍵のオペレーションにのみ適用されます。公開鍵オペレーションでは、認証は不要です。タイムアウトは再起動をまたぎません。再起動後は、すべての鍵が認証されていない状態になります。起動するたびに認証が必要であることを示すため、タイムアウトを大きな値(2^32 秒つまり約 136 年)に設定できます。Android デバイスはこれよりも頻繁に再起動されると考えられます。
デバイスのロック解除を必須にする
TAG::UNLOCKED_DEVICE_REQUIRED
を持つ鍵は、デバイスのロックが解除されている間にのみ使用できます。セマンティクスの詳細については、KeyProtection.Builder#setUnlockedDeviceRequired(boolean)
をご覧ください。
UNLOCKED_DEVICE_REQUIRED
は、Keymaster ではなくキーストアによって適用されます。ただし Android 12 以降、デバイスのロック中は、キーストアによって UNLOCKED_DEVICE_REQUIRED
鍵は暗号で保護されており、多くの場合は、デバイスのロック中にキーストアが侵害されたとしてもその鍵は使用できません。
これを実現するために、キーストアはすべての UNLOCKED_DEVICE_REQUIRED
鍵を「多重暗号化」してからデータベースに保存します。可能な場合は、デバイスのロック中に多重暗号鍵(スーパー鍵)を保護し、デバイスの正常なロック解除によってのみ復元できるようにします(この暗号レイヤは、Keymaster がすべての鍵に対してすでに適用している暗号レイヤに加えて適用されるために「多重暗号化」という用語が使用されます)。
各ユーザー(プロファイルを含む)は、UNLOCKED_DEVICE_REQUIRED
に関連付けられたスーパー鍵を 2 つ持っています。
- UnlockedDeviceRequired 対称スーパー鍵。これは AES‑256‑GCM 鍵です。デバイスがユーザーに対してロック解除されている間にインポートされたか、生成された
UNLOCKED_DEVICE_REQUIRED
鍵を暗号化します。 - UnlockedDeviceRequired 非対称スーパー鍵。これは、ECDH P‑521 鍵ペアです。デバイスがユーザーに対してロックされている間にインポートされたか、生成された
UNLOCKED_DEVICE_REQUIRED
鍵を暗号化します。この非対称鍵で暗号化された鍵は、初回使用時に対称鍵によって再暗号化されます(デバイスのロック解除中にのみ行われます)。
キーストアはこれらのスーパー鍵をユーザーの作成時に生成し、ユーザーの合成パスワードで暗号化してデータベースに保存します。これにより、ユーザーは PIN、パターン、パスワードに相当する方法を使用して復元が可能です。
また、キーストアはこれらのスーパー鍵をメモリ内にキャッシュし、UNLOCKED_DEVICE_REQUIRED
鍵で操作できるようにします。ただし、デバイスがユーザーに対してロック解除されている間にのみ、これらの鍵の非公開部分のキャッシュを試みます。デバイスがユーザーに対してロックされている間、可能な場合は、キーストアはキャッシュに保存されたスーパー鍵の非公開部分のコピーをゼロで抹消します。特に、デバイスがユーザーに対してロックされている間は、キーストアはユーザーの UnlockedDeviceRequired スーパー鍵の 3 つの保護レベルのうちいずれかを選択し、適用します。
- ユーザーが PIN、パターン、またはパスワードのみを有効にしている場合、キーストアはキャッシュに保存されたスーパー鍵の非公開部分をゼロで抹消します。このため、スーパー鍵は PIN、パターン、またはパスワードに相当する方法でのみ複合できるデータベースの暗号化されたコピーを介して復元が可能になります。
- ユーザーが、クラス 3(「強」)の生体認証と PIN、パターン、またはパスワードのみを有効にしている場合、キーストアは PIN、パターン、またはパスワードに相当するものの代わりとして、ユーザーが登録しているクラス 3 の生体認証(通常は指紋)によってスーパー鍵を復元できるようにします。これを実現するために、新しい AES‑256‑GCM 鍵を生成し、その鍵でスーパー鍵の非公開部分を暗号化して、AES‑256‑GCM 鍵を生体認証にバインドされた鍵として Keymaster にインポートします。生体認証にバインドされた鍵では、15 秒以内での生体認証の成功が必須であり、これらの鍵のすべての平文のコピーはゼロで抹消されます。
- ユーザーがクラス 1(「利便性」)の生体認証、クラス 2(「弱」)の生体認証、または能動的なロック解除の信頼エージェント有効にしている場合、キーストアはスーパー鍵を平文でキャッシュに保存したままにします。この場合、
UNLOCKED_DEVICE_REQUIRED
鍵に対する暗号セキュリティは提供されません。ユーザーはこれらのロック解除の方法を有効にしないことにより、安全面で劣るフォールバックを回避できます。これらのカテゴリに分類される最も一般的なロック解除の方法としては、多数のデバイスでの顔認証や、ペア設定されたスマートウォッチを使用してのロック解除があります。
ユーザーに対してデバイスがロック解除されると、キーストアは、可能な場合はユーザーの UnlockedDeviceRequired スーパー鍵を復元します。PIN、パターン、またはパスワードに相当するロック解除の場合、データベースに保存されている鍵のコピーが復号されます。それ以外の場合は、生体認証にバインドされた鍵で暗号化した鍵のコピーが保存されているかどうかを確認し、保存されている場合は復号を試みます。これは、(キーストアではなく)Keymaster によって適用されるもので、ユーザーが 15 秒以内にクラス 3 生体認証を使用して認証に成功した場合にのみ成功します。
クライアント バインディング
クライアント バインディングは、鍵を特定のクライアント アプリに関連付けることであり、オプションのクライアント ID とオプションのクライアント データ(それぞれ TAG::APPLICATION_ID
と TAG::APPLICATION_DATA
)を使用して実施します。キーストアは、これらの値を不透明な blob として扱います。鍵が使用されるたびに、鍵の生成 / インポート時に提示されたのと同じ blob が提示され、バイト単位で同一であることのみを保証します。クライアント バインディングのデータは、Keymaster から返されません。鍵を使用するには、呼び出し元が鍵を知っている必要があります。
この機能はアプリには公開されません。
有効期限
キーストアは、日付による鍵の使用制限をサポートします。鍵の有効期間の開始と終了の日時を鍵に関連付けることができます。現在の日時が有効期間外である場合、Keymaster は鍵オペレーションの実行を拒否します。鍵の有効期間は、タグ TAG::ACTIVE_DATETIME
、TAG::ORIGINATION_EXPIRE_DATETIME
、TAG::USAGE_EXPIRE_DATETIME
で指定します。「ORIGINATION」と「USAGE」の区別は、鍵を使用する目的が新しい暗号テキストや署名などを「創出」することなのか、それとも既存の暗号テキストや署名などを「使用」することなのかによります。この区別はアプリには公開されないことにご注意ください。
タグ TAG::ACTIVE_DATETIME
、TAG::ORIGINATION_EXPIRE_DATETIME
、TAG::USAGE_EXPIRE_DATETIME
はオプションです。これらのタグが存在しない場合、メッセージの復号 / 検証に常に該当の鍵を使用できると見なされます。
実測時間は非セキュア環境によって提供されるので、有効期間に関連するタグがハードウェア適用リストに追加されることはほとんどありません。ハードウェアで有効期限を適用する場合は、信頼できるリモート タイムサーバーを使用したチャレンジ応答プロトコルなどの方法により、信頼できる時間とデータをセキュア環境で取得する必要があります。
ルート オブ トラスト バインディング
キーストアは、鍵がルート オブ トラストにバインドされることを要求します。ルート オブ トラストは、起動時に Keymaster セキュア ハードウェアに対して提供される、ブートローダーによって提供することが望ましいビット文字列です。このビット文字列は、Keymaster が管理するすべての鍵に暗号としてバインドされます。
ルート オブ トラストは、ブートイメージの署名の検証に使用される公開鍵と、デバイスのロック状態の情報で構成されます。別のシステム イメージの使用を許可するために公開鍵が変更された場合またはロック状態が変更された場合、変更前のルート オブ トラストが復元され、その鍵で署名されたシステムが起動されない限り、変更前のシステムで作成された、Keymaster が保護する鍵は使用できません。この機能の目的は、攻撃者がインストールしたオペレーティング システムが Keymaster の鍵を使用できないようにすることにより、ソフトウェアで適用される鍵アクセス制御の効果を高めることです。
スタンドアロン鍵
Keymaster セキュア ハードウェアは、鍵マテリアルを内部的に保存し、暗号化された鍵マテリアルの代わりにハンドルを返すことがあります。また、他の非セキュアまたはセキュア環境のシステム コンポーネントが使用可能になるまで鍵を使用できないこともあります。Keymaster HAL を使用して、呼び出し元は TAG::STANDALONE
タグにより鍵が「スタンドアロン」であることを要求できます。これは、blob および実行中の Keymaster システム以外のリソースが不要であることを意味します。鍵に関連付けられたタグを検査すると、鍵がスタンドアロンかどうかを確認できます。現在のところ、次の 2 つの値のみが定義されています。
KeyBlobUsageRequirements::STANDALONE
KeyBlobUsageRequirements::REQUIRES_FILE_SYSTEM
この機能はアプリには公開されません。
速度
鍵の作成時に、TAG::MIN_SECONDS_BETWEEN_OPS
で最大使用速度を指定できます。
TrustZone 実装は、TAG::MIN_SECONDS_BETWEEN_OPS
秒より早くオペレーションが実行された場合、その鍵の暗号オペレーションを拒否します。
速度制限を実装する簡単な方法は、鍵 ID と最終使用タイムスタンプのテーブルを使用することです。このテーブルはサイズが制限されますが、少なくとも 16 エントリは入力できます。テーブルがいっぱいでエントリの更新または破棄ができない場合、セキュア ハードウェア実装は「フェイルセーフ」策をとり、エントリの 1 つが期限切れになるまで速度制限鍵のオペレーションをすべて拒否することを選びます。再起動時には、すべてのエントリが有効期限切れになることが適切です。
TAG::MAX_USES_PER_BOOT
により、鍵の使用を 1 回の起動につき n 件に制限することもできます。そのためにはトラッキング テーブルが必要です。このテーブルは少なくとも 4 つのキーに対応し、フェイルセーフ仕様です。この種の起動制限鍵はアプリでは作成できないことにご注意ください。この機能は、キーストアでは公開されておらず、システム オペレーション用に予約されています。
この機能はアプリには公開されません。
乱数ジェネレータの再シーディング
セキュア ハードウェアは鍵マテリアルと初期化ベクトル(IV)用の乱数を生成しますが、ハードウェア乱数ジェネレータは必ずしも完全には信頼できないため、Keymaster HAL は、生成された乱数に混合される追加のエントロピーをクライアントが提供するためのインターフェースを備えています。
ハードウェア乱数ジェネレータがプライマリ シードソースとして使用されます。 外部 API を通じて提供されるシードデータは、数値の生成に使用されるランダム性の唯一のソースにすることはできません。さらに、使用される混合オペレーションでは、いずれか一方のシードソースが予測不可能である場合、ランダム出力が予測不可能になることを保証する必要があります。
この機能はアプリには公開されませんが、フレームワークによって使用されます。これにより、Java SecureRandom インスタンスから取得した追加のエントロピーがセキュアなハードウェアに定期的に提供されます。