機能

このページでは、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
    • 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::ENCRYPTKeyPurpose::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::ALGORITHMTAG::KEY_SIZETAG::BLOCK_MODETAG::PADDINGTAG::CALLER_NONCETAG::DIGEST

TAG::PADDINGTAG::DIGESTPaddingMode::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_IDTAG::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 デバイスはおそらく頻繁に再起動されると考えられます。

クライアント バインディング

クライアント バインディングは、鍵を特定のクライアント アプリに関連付けることであり、オプションのクライアント ID とオプションのクライアント データ(それぞれ TAG::APPLICATION_IDTAG::APPLICATION_DATA)を使用して実施します。キーストアは、これらの値を不透明な blob として扱います。鍵が使用されるたびに、鍵の生成 / インポート時に提示されたのと同じ blob が提示され、バイト単位で同一であることのみを保証します。クライアント バインディングのデータは、Keymaster から返されません。鍵を使用するには、呼び出し元が鍵を知っている必要があります。

この機能はアプリには公開されません。

有効期限

キーストアは、日付による鍵の使用制限をサポートします。鍵の有効期間の開始と終了の日時を鍵に関連付けることができます。現在の日時が有効期間外である場合、Keymaster は鍵オペーションの実行を拒否します。鍵の有効期間は、タグ TAG::ACTIVE_DATETIMETAG::ORIGINATION_EXPIRE_DATETIMETAG::USAGE_EXPIRE_DATETIME で指定します。「ORIGINATION」と「USAGE」の区別は、鍵を使用する目的が新しい暗号テキストや署名などを「創出」することなのか、それとも既存の暗号テキストや署名などを「使用」することなのかによります。この区別はアプリには公開されないことにご注意ください。

タグ TAG::ACTIVE_DATETIMETAG::ORIGINATION_EXPIRE_DATETIMETAG::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 インスタンスから取得された追加のエントロピーを定期的にセキュア ハードウェアに提供するフレームワークで使用されます。