Android 7.0 以降では、ファイルベースの暗号化(FBE)がサポートされています。 ファイルベースの暗号化を使用すると、さまざまなファイルを異なる鍵で暗号化して、個別にロック解除できます。
この記事では、新しいデバイスでファイルベースの暗号化を有効にする方法と、システムアプリが Direct Boot API を使用して、可能な限り安全性の高い最適な操作性をユーザーに提供する仕組みについて説明します。
ダイレクト ブート
ファイルベースの暗号化により、Android 7.0 で導入されたダイレクト ブートという新機能が有効化されます。ダイレクト ブートでは、暗号化されたデバイスをロック画面に直接起動できます。これまで、フルディスク暗号化(FDE)を使用して暗号化されたデバイスでは、認証情報を提供しないとデータに一切アクセスできず、ごく基本的な操作を除いて、スマートフォンでほとんどの操作を行えませんでした。たとえば、アラームを操作することも、ユーザー補助サービスを利用することもできず、緊急通報操作を除いてスマートフォンで通話を受信することもできません。
ファイルベースの暗号化(FBE)と、アプリが暗号化を認識できるようにする新しい API の導入により、限られたコンテキスト内でアプリが動作できるようになりました。ユーザーが認証情報を提供する前に、個人情報を保護したままでこの動作が実現します。
FBE 対応デバイスでは、デバイスの各ユーザーが 2 つの保存場所をアプリで使用できます。
- デフォルトの保存先であり、ユーザーがデバイスのロックを解除した後にだけ使用できる認証情報暗号化(CE)ストレージ。
- ダイレクト ブート モード中とユーザーがデバイスのロックを解除した後の両方で保存先として使用できるデバイス暗号化(DE)ストレージ。
暗号化が起動時のパスワードのみに基づくものではなくなり、この分離によって複数のユーザーを一度に保護できるため、仕事用プロファイルの安全性が高まります。
Direct Boot API を使用すると、暗号化対応のアプリがこれらの領域にアクセスできます。ロック画面に認証情報が最初に入力された際の応答として、または仕事用プロファイルでワーク チャレンジが提供された場合に、ユーザーの CE ストレージがロック解除されたことをアプリに通知できるようにアプリのライフサイクルが変更されています。Android 7.0 搭載デバイスは、FBE を実装しているかどうかにかかわらず、新しい API とライフサイクルをサポートする必要があります。ただし、FBE が実装されていない場合は、DE ストレージと CE ストレージが常にロック解除状態になります。
Android オープンソース プロジェクト(AOSP)で提供されている、Ext4 と F2FS のファイルシステムに対するファイルベースの暗号化の完全な実装は、要件を満たすデバイスでのみ有効です。FBE の使用を選択したメーカーは、使用するシステム オン チップ(SoC)に基づいて機能を最適化する方法を検討できます。
AOSP 内で対応の必要なパッケージはすべて、ダイレクトブート対応に更新されています。 ただし、デバイス メーカーがこれらのアプリのカスタマイズ版を使用する場合、次のサービスを提供するダイレクトブート対応パッケージが最低限必要になります。
- 電話サービスと電話アプリ
- ロック画面にパスワードを入力するための入力方法
例とソース
Android にはファイルベースの暗号化のリファレンス実装が用意されており、vold(system/vold)によって Android のストレージ デバイスとボリュームを管理する機能が提供されます。FBE を追加すると、複数のユーザーの CE 鍵と DE 鍵の管理に対応したいくつかの新しいコマンドが vold に提供されます。カーネルでファイルベースの暗号化機能を使用するための主な変更に加え、ロック画面と SystemUI を含む多くのシステム パッケージが、FBE とダイレクト ブート機能をサポートするように変更されました。次のような機能があります。
- AOSP 電話アプリ(packages/apps/Dialer)
- 時計(packages/apps/DeskClock)
- LatinIME(packages/inputmethods/LatinIME)*
- 設定アプリ(packages/apps/Settings)*
- SystemUI(frameworks/base/packages/SystemUI)*
* defaultToDeviceProtectedStorage
マニフェスト属性を使用するシステムアプリ
暗号化に対応しているアプリとサービスのその他の例は、AOSP ソースツリーのフレームワークまたはパッケージ ディレクトリでコマンド mangrep directBootAware
を実行することで確認できます。
依存関係
FBE の AOSP 実装を安全に使用するには、デバイスが次の依存関係を満たしている必要があります。
- Ext4 暗号化または F2FS 暗号化のカーネル サポート。
- HAL バージョン 1.0 または 2.0 の Keymaster サポート。Keymaster 0.3 は、必要な機能を提供しなかったり、暗号鍵の保護が不十分であったりするため、サポートされていません。
- Keymaster またはキーストアとゲートキーパーを Trusted Execution Environment(TEE)に実装して DE 鍵を保護し、未承認の OS(デバイスにフラッシュされたカスタム OS)が簡単に DE 鍵を要求できないようにする必要があります。
- 未承認のオペレーティング システムがデバイス暗号化の認証情報にアクセスできないようにするには、Keymaster の初期化にバインドされたハードウェア ルート オブ トラストと確認付きブートが必要です。
注: ストレージ ポリシーはフォルダとそのすべてのサブフォルダに適用されます。メーカーは暗号化しないコンテンツを、OTA フォルダと、システムを復号する鍵を保持するフォルダに制限する必要があります。ほとんどのコンテンツは、デバイス暗号化ストレージではなく認証情報暗号化ストレージに保存する必要があります。
実装
まずは、ダイレクト ブートのデベロッパー向けドキュメントに基づいて、アラーム、電話、ユーザー補助機能などのアプリを android:directBootAware にする必要があります。
カーネル サポート
Ext4 と F2FS の暗号化向けのカーネル サポートは、Android 共通カーネルのバージョン 3.18 以降で利用できます。バージョン 5.1 以降のカーネルでこのカーネル サポートを有効にする場合は、以下を使用します。
CONFIG_FS_ENCRYPTION=y
バージョン 5.1 より前のカーネルの場合、デバイスの userdata
ファイル システムが Ext4 であれば CONFIG_EXT4_ENCRYPTION=y
を使用し、デバイスの userdata
ファイル システムが F2FS であれば CONFIG_F2FS_FS_ENCRYPTION=y
を使用します。
デバイスが Adoptable Storage をサポートする場合や、内部ストレージのメタデータ暗号化を使用する場合は、メタデータ暗号化に必要なカーネル構成オプションも有効にします。詳細については、メタデータ暗号化に関するドキュメントをご覧ください。
ファイルベース暗号化を高速化し、ユーザー エクスペリエンスを高めるため、デバイス メーカーは、Ext4 / F2FS 暗号化の機能サポートに加えて、暗号アクセラレーションも有効にする必要があります。たとえば ARM64 ベースのデバイスでは、次のカーネル構成オプションを設定することによって ARMv8 CE(暗号拡張機能)のアクセラレーションを有効にできます。
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_SHA2_ARM64_CE=y
デバイス メーカーは、さらなるパフォーマンスの向上と電力消費量の削減のために、ストレージ デバイスとの間でデータを伝送する際にデータの暗号化と復号を行う「インライン暗号化ハードウェア」の実装を検討することもできます。Android 共通カーネル(バージョン 4.14 以降)には、ハードウェアとベンダー ドライバのサポートが利用可能な場合にインライン暗号化を使用できるようにするフレームワークが搭載されています。インライン暗号化フレームワークを有効にするには、以下のカーネル構成オプションを設定します。
CONFIG_BLK_INLINE_ENCRYPTION=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
デバイスで UFS ベースのストレージを使用する場合は、次のオプションも有効にします。
CONFIG_SCSI_UFS_CRYPTO=y
デバイスで eMMC ベースのストレージを使用する場合は、次のオプションも有効にします。
CONFIG_MMC_CRYPTO=y
ファイルベースの暗号化の有効化
デバイスで FBE を有効にする場合、内部ストレージ(userdata
)で有効にする必要があります。これにより、Adoptable Storage でも FBE が自動的に有効化されます。ただし、Adoptable Storage での暗号化形式は、必要に応じてオーバーライドされることがあります。
内部ストレージ
FBE を有効にするには、userdata
の fstab
行の fs_mgr_flags 列にオプション fileencryption=contents_encryption_mode[:filenames_encryption_mode[:flags]]
を追加します。このオプションでは、内部ストレージでの暗号化形式を定義します。オプションには最大 3 つのパラメータを含めることができます(コロンで区切って指定)。
contents_encryption_mode
パラメータでは、ファイルの内容の暗号化に使用される暗号アルゴリズムを定義します。aes-256-xts
またはadiantum
のいずれかを指定できます。filenames_encryption_mode
パラメータでは、ファイル名の暗号化に使用される暗号アルゴリズムを定義します。aes-256-cts
、aes-256-heh
、adiantum
のいずれかを指定できます。指定しない場合のデフォルトは、contents_encryption_mode
がaes-256-xts
の場合はaes-256-cts
、contents_encryption_mode
がadiantum
の場合はadiantum
です。- Android 11 で新たに導入された
flags
パラメータでは、フラグのリストを指定します(+
記号で区切って指定)。次のフラグがサポートされています。v1
フラグを指定するとバージョン 1 の暗号化ポリシーが、v2
フラグを指定するとバージョン 2 の暗号化ポリシーが選択されます。バージョン 2 の暗号化ポリシーでは、安全性と柔軟性に優れた鍵導出関数が使用されます。デフォルトは、Android 11 以降を搭載して出荷されたデバイス(ro.product.first_api_level
によって特定される)の場合は v2、Android 10 以前を搭載して出荷されたデバイスの場合は v1 です。inlinecrypt_optimized
フラグを指定すると、多数の鍵を効率的に処理できないインライン暗号化ハードウェア向けに最適化された暗号化形式が選択されます。これは、ファイルの内容の暗号化に使用する鍵を、ファイルごとに 1 つではなく、CE 鍵または DE 鍵ごとに 1 つだけ派生させることによって行われます。IV(初期化ベクトル)の生成は適宜調整されます。emmc_optimized
フラグはinlinecrypt_optimized
と同様ですが、IV を 32 ビットに制限する IV 生成メソッドも選択することになります。このフラグは、JEDEC eMMC v5.2 仕様に従って 32 ビットの IV のみサポートするインライン暗号化ハードウェアでのみ使用してください。他のインライン暗号化ハードウェアでは、代わりにinlinecrypt_optimized
を使用します。このフラグは UFS ベースのストレージでは使用できません。UFS 仕様では、64 ビットの IV を使用できます。wrappedkey_v0
フラグを指定すると、ハードウェアでラップされた鍵を使用できるようになります。このフラグを有効にした場合、FBE 鍵はソフトウェアでは生成されず、Keymaster でSTORAGE_KEY
タグを使用することによって生成されます。さらに、実際にカーネルに提供される各 FBE 鍵は、Keymaster からエクスポートされるSTORAGE_KEY
鍵です。そのため、各鍵が起動ごとのエフェメラル鍵でラップされます。カーネルはその後、ラップされた鍵をインライン暗号化ハードウェアに直接提供します。実装が適切であれば、ラップ解除された鍵がシステムメモリ内に存在することはないため、ラップされた不正な鍵を再起動後に使用することはできません。このフラグを使用する場合、ハードウェアのサポート、STORAGE_KEY
に対する Keymaster のサポート、カーネル ドライバのサポート、inlinecrypt
マウント オプションのほか、inlinecrypt_optimized
フラグとemmc_optimized
フラグのどちらかが必要です。
インライン暗号化ハードウェアを使用していない場合、ほとんどのデバイスでは、fileencryption=aes-256-xts
を設定することをおすすめします。インライン暗号化ハードウェアを使用している場合、ほとんどのデバイスでは、fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized
を設定することをおすすめします。どの形式の AES アクセラレーションも使用していないデバイスでは、fileencryption=adiantum
を設定することにより、AES の代わりに Adiantum を使用できます。
Android 10 以前を搭載して出荷されたデバイスでは、fileencryption=ice
を指定することで、ファイルの内容の暗号化モードとして FSCRYPT_MODE_PRIVATE
を使用することもできます。このモードは Android 共通カーネルでは実装されませんが、ベンダーがカスタムのカーネルパッチを使用して実装することはできました。このモードで生成されるディスク上の暗号化形式はベンダー固有だったのです。Android 11 以降を搭載して出荷されるデバイスでは、このモードは使用できなくなりました。代わりに、標準の暗号化形式を使用する必要があります。
デフォルトでは、ファイルの内容の暗号化は Linux カーネルの暗号 API を使用して行われます。インライン暗号化ハードウェアを使用する場合も、inlinecrypt
マウント オプションを追加します。たとえば、完全な fstab
行は次のようになります。
/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,errors=panic,inlinecrypt wait,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized
Adoptable Storage
Android 9 以降では、FBE と Adoptable Storage を組み合わせて使用できます。
また、userdata
に対して fileencryption
fstab オプションを指定すると、Adoptable Storage で FBE とメタデータ暗号化の両方が自動的に有効化されます。ただし Adoptable Storage では、PRODUCT_PROPERTY_OVERRIDES
のプロパティを設定することで、FBE またはメタデータ暗号化(あるいはその両方)の形式をオーバーライドできます。
Android 11 以降を搭載して出荷されたデバイスでは、次のプロパティを使用します。
ro.crypto.volume.options
(Android 11 で新たに導入されたプロパティ): Adoptable Storage で FBE 暗号化形式を選択します。このプロパティは、fileencryption
fstab オプションに対する引数と構文が同じであるため、同じデフォルトを使用します。 このプロパティで使用する内容については、上記のfileencryption
に関する推奨事項をご覧ください。ro.crypto.volume.metadata.encryption
: Adoptable Storage のメタデータ暗号化形式を選択します。詳細については、メタデータ暗号化をご覧ください。
Android 10 以前を搭載して出荷されたデバイスの場合、以下のプロパティを使用します。
ro.crypto.volume.contents_mode
: ファイルの内容の暗号化モードを選択します。これは、ro.crypto.volume.options
の最初のコロン区切りのフィールドと同じです。ro.crypto.volume.filenames_mode
: ファイル名の暗号化モードを選択します。これは、Android 10 以前を搭載して出荷されたデバイスのデフォルトがaes-256-heh
であることを除き、ro.crypto.volume.options
の 2 番目のコロン区切りのフィールドと同じです。ほとんどのデバイスでは、このデフォルトを明示的にオーバーライドしてaes-256-cts
にする必要があります。ro.crypto.fde_algorithm
とro.crypto.fde_sector_size
: Adoptable Storage のメタデータ暗号化形式を選択します。詳細については、メタデータ暗号化をご覧ください。
Keymaster との統合
鍵の生成とカーネル キーリングの管理は、vold
によって行われます。FBE の AOSP 実装では、デバイスが Keymaster HAL バージョン 1.0 以降をサポートしている必要があります。以前のバージョンの Keymaster HAL はサポートされません。
最初の起動時にユーザー 0 の鍵が生成され、起動プロセスの初期段階でインストールされます。init
の on-post-fs
フェーズが完了するまでに、Keymaster でリクエストを処理する準備ができている必要があります。Pixel デバイスでは、スクリプト ブロックを使用して /data
のマウント前に Keymaster を起動させることでこれを実現します。
暗号化ポリシー
ファイルベースの暗号化では、ディレクトリ レベルで暗号化ポリシーが適用されます。デバイスの userdata
パーティションが最初に作成されると、基本構造とポリシーが init
スクリプトによって適用されます。これらのスクリプトは、最初のユーザー(ユーザー 0)の CE 鍵と DE 鍵の作成をトリガーし、さらにこれらの鍵で暗号化するディレクトリを定義します。追加のユーザーとプロファイルが作成されると、必要な鍵が追加で生成されてキーストアに保存されます。認証情報とデバイスの保存場所が作成され、暗号化ポリシーによってこれらの鍵がディレクトリにリンクされます。
Android 11 以降では、暗号化ポリシーが一元管理された場所にハードコードされなくなりましたが、init スクリプトの mkdir
コマンドへの引数で定義されるようになりました。システムの DE 鍵で暗号化されたディレクトリでは encryption=Require
が使用されるのに対し、暗号化されていないディレクトリ(または、サブディレクトリがユーザー別の鍵で暗号化されたディレクトリ)では encryption=None
が使用されます。
Android 10 では、暗号化ポリシーは次の場所にハードコードされていました。
/system/extras/libfscrypt/fscrypt_init_extensions.cpp
Android 9 以前では、次の場所にハードコードされていました。
/system/extras/ext4_utils/ext4_crypt_init_extensions.cpp
例外を追加して、特定のディレクトリが暗号化されないようにすることもできます。このような変更を行う場合、デバイス メーカーは暗号化されていないディレクトリを使用するアプリにのみアクセスを許可する SELinux ポリシーを含める必要があります。これにより、信頼できないアプリがすべて除外されます。
なお、従来の OTA 機能のサポートに含まれるのは既知の利用可能なユースケースのみです。
システムアプリでのダイレクト ブートのサポート
アプリをダイレクト ブート対応にする
システムアプリの迅速な移行を実現するために、アプリレベルで設定できる新しい属性が 2 つあります。defaultToDeviceProtectedStorage
属性はシステムアプリでのみ使用できます。directBootAware
属性はすべてのアプリに使用できます。
<application android:directBootAware="true" android:defaultToDeviceProtectedStorage="true">
アプリレベルの directBootAware
属性は、簡単にアプリ内のすべてのコンポーネントを暗号化対応にする方法です。
defaultToDeviceProtectedStorage
属性は、CE ストレージではなく DE ストレージを指すように、デフォルトのアプリの保存場所をリダイレクトします。
このフラグを使用するシステムアプリは、デフォルトの場所に保存されたすべてのデータを慎重に監査し、CE ストレージを使用するように機密データのパスを変更する必要があります。この方法を使用するデバイス メーカーは、保存するデータを慎重に調べて、個人情報が含まれていないことを確認する必要があります。
このモードを実行する場合は、次のシステム API を使用して、必要に応じて CE ストレージに保持されたコンテキストを明示的に管理できます。これは、デバイス保護ストレージに相当します。
Context.createCredentialProtectedStorageContext()
Context.isCredentialProtectedStorage()
複数のユーザーをサポートする
マルチユーザー環境の各ユーザーは個別の暗号鍵を取得します。すべてのユーザーが DE と CE の 2 つの鍵を取得します。ユーザー 0 は特別なユーザーであるため、最初にデバイスにログインする必要があります。これは、デバイス管理の使用に関係します。
暗号化対応アプリは、INTERACT_ACROSS_USERS
と INTERACT_ACROSS_USERS_FULL
(アプリがデバイス上のすべてのユーザー間で動作できるようにする)によってユーザー間で動作します。ただしこれらのアプリがアクセスできるのは、すでにロック解除されているユーザーの CE で暗号化されたディレクトリのみです。
アプリは DE エリア間で自由に動作できますが、1 人のユーザーがロック解除されていても、デバイス上のすべてのユーザーがロック解除されているわけではありません。アプリはこのステータスを確認してから、これらの領域にアクセスする必要があります。
仕事用プロファイルの各ユーザー ID にも、DE と CE の 2 つの鍵があります。ワーク チャレンジが満たされると、プロファイルのユーザーがロック解除され、TEE 内の Keymaster はプロファイルの TEE 鍵を提供できます。
アップデートの処理
リカバリ パーティションは、ユーザーデータ パーティションの DE で保護されたストレージにアクセスできません。FBE を実装するデバイスでは、A/B システムアップデートを使用した OTA をサポートすることを強くおすすめします。通常の動作中に OTA を適用できるため、暗号化されたドライブ上のデータにリカバリがアクセスする必要はありません。
以前の OTA ソリューションを使用している場合は、リカバリが userdata
パーティション上の OTA ファイルにアクセスする必要があります。
userdata
パーティションに最上位ディレクトリ(misc_ne
など)を作成します。- この最上位ディレクトリを暗号化ポリシーの例外に追加します(上の暗号化ポリシーを参照)。
- OTA パッケージを格納するディレクトリを最上位ディレクトリ内に作成します。
- SELinux ルールとファイル コンテキストを追加して、このフォルダとそのコンテンツへのアクセスを制御します。OTA アップデートを受信するプロセスまたはアプリのみが、このフォルダの読み取りと書き込みを行える必要があります。他のアプリやプロセスがこのフォルダにアクセスできないようにしてください。
検証
機能の実装バージョンが意図したとおりに動作することを確認するには、多数の CTS 暗号化テスト(DirectBootHostTest、EncryptionTest など)を使用します。
Android 11 以降が搭載されているデバイスの場合は、vts_kernel_encryption_test も使用します。
atest vts_kernel_encryption_test
または
vts-tradefed run vts -m vts_kernel_encryption_test
デバイス メーカーは次の手動テストを実施することもできます。FBE が有効になっているデバイスで以下を実施します。
ro.crypto.state
をチェックしますro.crypto.state
が暗号化されていることを確認します
ro.crypto.type
をチェックしますro.crypto.type
がfile
に設定されていることを確認します
テストでは、メインユーザーに対して設定されたロック画面を使用して userdebug
インスタンスを起動することもできます。次に、adb
シェルでデバイスに接続し、su
を使用して root になります。暗号化されたファイル名が /data/data
に含まれていることを確認してください。含まれていない場合は、なんらかの異常があります。
また、デバイス メーカーは、自社のデバイスまたはカーネルで Linux の fscrypt 用アップストリーム テストを実行することをおすすめします。このテストは、xfstests ファイルシステムのテストスイートの一部です。ただし、上記アップストリーム テストは Android では公式にはサポートされていません。
AOSP 実装の詳細
このセクションでは、AOSP 実装の詳細とファイルベースの暗号化の仕組みについて説明します。デバイス メーカーが自社のデバイスで FBE とダイレクト ブートを使用するために、変更を加える必要はありません。
fscrypt 暗号化
AOSP 実装では、カーネルで「fscrypt」暗号化(ext4 と f2fs でサポートされている)が使用されます。これは通常、次のように設定されています。
- XTS モードの AES-256 でファイルの内容を暗号化します
- CBC-CTS モードの AES-256 でファイル名を暗号化します
Adiantum 暗号化もサポートされています。Adiantum 暗号化が有効になっている場合、ファイルの内容とファイル名はどちらも Adiantum で暗号化されます。
fscrypt について詳しくは、アップストリーム カーネルのドキュメントをご覧ください。
鍵の派生
512 ビットの鍵であるファイルベースの暗号鍵は、TEE に保持された別の鍵(256 ビット AES-GCM 鍵)で暗号化されてから保存されます。この TEE 鍵を使用するには、次の 3 つの要件を満たす必要があります。
- 認証トークン
- 伸長された認証情報
- secdiscardable hash
認証トークンは、ユーザーが正常にログインしたときにゲートキーパーによって生成される、暗号を用いて認証されたトークンです。正しい認証トークンが指定されていない場合、TEE は鍵の使用を拒否します。ユーザーに認証情報がない場合、認証トークンは使用されず、必要もありません。
伸長された認証情報とは、scrypt
アルゴリズムによってソルト化と伸長が行われた後のユーザー認証情報です。実際には、認証情報はロック設定サービスで一旦ハッシュ化されてから、scrypt
に渡すために vold
に渡されます。これは、KM_TAG_APPLICATION_ID
に適用されるすべての保証とともに TEE 内の鍵に暗号的にバインドされます。ユーザーに認証情報がない場合、伸長された認証情報は使用されず、必要もありません。
secdiscardable hash
はランダムな 16 KB ファイルの 512 ビットのハッシュで、シードなどの鍵を再構築するために使用される他の情報と一緒に格納されます。このファイルは、鍵が削除されるか新しい方法で暗号化された場合に安全に削除されます。この強化された保護により、攻撃者が鍵を復元するには、安全に削除されたファイルのすべてのビットを復元する必要があります。これは、KM_TAG_APPLICATION_ID
に適用されるすべての保証とともに TEE 内の鍵に暗号的にバインドされます。
ほとんどの場合、FBE 鍵では、暗号化で実際に使用されるサブ鍵(ファイル別またはモード別の鍵など)を生成するために、カーネル内で追加の鍵派生処理も実行されます。バージョン 2 の暗号化ポリシーでは、HKDF-SHA512 がこの処理に使用されます。