Android 7.0 以降では、ファイルベースの暗号化(FBE)がサポートされています。FBE を使用すると、さまざまなファイルをそれぞれ異なる鍵で暗号化して、個別にロック解除できます。これらの鍵は、ファイルの内容と名前の両方を暗号化するために使用されます。 FBE を使用した場合、ディレクトリ レイアウトやファイルサイズ、パーミッション、作成日時 / 変更日時など、他の情報は暗号化されません。このような他の情報は、総称して「ファイル システム メタデータ」と呼ばれます。
Android 9 で、メタデータ暗号化がサポートされるようになりました。 メタデータ暗号化は、FBE によって暗号化されないコンテンツを、ブート時に提供される 1 つの鍵で暗号化します。この鍵は Keymaster によって保護され、Keymaster は確認付きブートによって保護されます。
Adoptable Storage の場合、FBE を有効にすると、必ずメタデータ暗号化も有効になります。また、メタデータ暗号化は、内部ストレージに対して有効にすることもできます。Android 11 以降を搭載してリリースされたデバイスでは、内部ストレージに対してメタデータ暗号化を有効にする必要があります。
内部ストレージに対する実装
新しいデバイスの内部ストレージに対してメタデータ暗号化をセットアップするには、metadata
ファイル システムをセットアップして、init シーケンスを変更し、デバイスの fstab ファイル内でメタデータ暗号化を有効にします。
要件
メタデータ暗号化をセットアップできるのは、データ パーティションを最初にフォーマットするときに限られます。そのため、この機能は新しいデバイス専用であり、OTA で変更するものではありません。
メタデータ暗号化を使用するには、カーネル内で dm-default-key
モジュールを有効にする必要があります。Android 11 以降の場合、dm-default-key
は、Android 共通カーネル(バージョン 4.14 以降)によってサポートされています。このバージョンの dm-default-key
は、ハードウェアとベンダーに依存しない暗号化フレームワーク「blk-crypto」を使用します。
dm-default-key
を有効にするには、以下を使用します。
CONFIG_BLK_INLINE_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_DM_DEFAULT_KEY=y
dm-default-key
は、利用可能な場合、インライン暗号化ハードウェア(ストレージ デバイスと送受信している最中にデータの暗号化 / 復号を行うハードウェア)を使用します。インライン暗号化ハードウェアを使用しない場合は、カーネルの暗号化 API に対するフォールバックも有効にする必要があります。
CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y
インライン暗号化ハードウェアを使用しない場合は、FBE で推奨されているとおり、CPU ベース アクセラレーションも有効にしてください。
Android 10 以前の場合、dm-default-key
は、Android 共通カーネルによってサポートされていませんでした。そのため、dm-default-key
の実装はベンダーに任されていました。
メタデータ ファイル システムのセットアップ
メタデータ暗号鍵がないとユーザーデータ パーティション内のデータを読み取れないため、この鍵を保護する keymaster blob を格納できるように、パーティション テーブルに「メタデータ パーティション」という独立したパーティションを確保する必要があります。メタデータ パーティションには 16 MB 必要です。
fstab.hardware
には、起動時にフォーマットされていることを保証する formattable
フラグを含む、/metadata
でマウントされるパーティションに存在するメタデータ ファイルシステムのエントリを含める必要があります。f2fs ファイルシステムは小さいパーティションでは動作しないため、代わりに ext4 を使用することをおすすめします。次に例を示します。
/dev/block/bootdevice/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard wait,check,formattable
/metadata
マウント ポイントが確実に存在するように、次の行を BoardConfig-common.mk
に追加します。
BOARD_USES_METADATA_PARTITION := true
init シーケンスの変更
メタデータ暗号化を使用する場合、/data
がマウントされるためには、まず vold
が実行されている必要があります。早期に開始されるように、次のスタンザを init.hardware.rc
に追加します。
# We need vold early for metadata encryption on early-fs start vold
init が /data
のマウントを試行するには、Keymaster が動作して準備が整っている必要があります。
init.hardware.rc
の on
late-fs
スタンザには、/data
自体をマウントする mount_all
命令がすでに含まれています。この行の前に、wait_for_keymaster
サービスを実行するディレクティブを追加します。
on late-fs … # Wait for keymaster exec_start wait_for_keymaster # Mount RW partitions which need run fsck mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late
メタデータ暗号化の有効化
最後に、userdata
の fstab
エントリの fs_mgr_flags 列に keydirectory=/metadata/vold/metadata_encryption
を追加します。たとえば、完全な fstab 行は次のようになります。
/dev/block/bootdevice/by-name/userdata /data f2fs noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable
内部ストレージのメタデータ暗号化アルゴリズムは、デフォルトでは AES-256-XTS です。この設定は、同様に fs_mgr_flags 列で metadata_encryption
オプションを設定することでオーバーライドできます。
- AES アクセラレーションを搭載していないデバイスの場合、
metadata_encryption=adiantum
を設定することで、Adiantum 暗号化を有効にできます。 - ハードウェアでラップされた鍵をサポートしているデバイスでは、
metadata_encryption=aes-256-xts:wrappedkey_v0
(または、aes-256-xts
がデフォルトのアルゴリズムであるため同等のmetadata_encryption=:wrappedkey_v0
)を設定すると、メタデータ暗号鍵をハードウェアでラップできます。
Android 11 では dm-default-key
へのカーネル インターフェースが変更されたため、device.mk
の PRODUCT_SHIPPING_API_LEVEL
に正しい値が設定されるようにする必要もあります。たとえば、デバイスが Android 11(API レベル 30)で起動する場合、device.mk
に以下を含めます。
PRODUCT_SHIPPING_API_LEVEL := 30
次のようにシステム プロパティを設定して、出荷時の API レベルに関係なく、新しい dm-default-key
API を使用するように強制することもできます。
PRODUCT_PROPERTY_OVERRIDES += \ ro.crypto.dm_default_key.options_format.version=2
検証
以下のコマンドを実行して、メタデータ暗号化が有効になっているか、そして正常に動作するか検証します。また、以下で説明するよくある問題にも注意してください。
テスト
まず、次のコマンドを実行して、内部ストレージでメタデータの暗号化が有効になっていることを確認します。
adb root
adb shell dmctl table userdata
出力は次のようになります。
Targets in the device-mapper table for userdata: 0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors
デバイスの fstab
で metadata_encryption
オプションを設定してデフォルトの暗号化設定をオーバーライドした場合の出力は、上記と少し異なります。たとえば、Adiantum 暗号化を有効にしている場合、3 番目のフィールドは aes-xts-plain64
ではなく xchacha12,aes-adiantum-plain64
になります。
次に、vts_kernel_encryption_test を実行して、メタデータの暗号化と FBE の正確性を確認します。
atest vts_kernel_encryption_test
または
vts-tradefed run vts -m vts_kernel_encryption_test
よくある問題
メタデータ暗号化済みの /data
パーティションをマウントする mount_all
の呼び出し中に、init
が vdc ツールを実行します。vdc ツールは、binder
を介して vold
に接続し、メタデータ暗号化済みのデバイスを設定してパーティションをマウントします。この呼び出しの間は init
がブロックされ、init
プロパティの読み取りまたは設定の試行は、mount_all
が終了するまでブロックされます。
この段階で、プロパティの読み取りまたは設定に関する vold
のいずれかの作業が直接的または間接的にブロックされると、デッドロックが発生します。vold
が init
の介入なしで、鍵の読み取り、Keymaster とのやり取り、データ ディレクトリのマウントを完了できることが重要です。
Keymaster は mount_all
の実行時に完全に起動していないと、init
から特定のプロパティを読み込むまで vold
に応答しません。その結果、上述のデッドロックが発生します。前述したように、関連する mount_all
呼び出しの上に exec_start wait_for_keymaster
を追加すると、事前に Keymaster が完全に動作して、このデッドロックを回避できます。
Adoptable Storage 上の構成
Android 9 以降の場合、内部ストレージに対してメタデータ暗号化が有効になっていなくても、FBE が有効になっている場合は常に Adoptable Storage に対してメタデータ暗号化が有効になります。
AOSP では、Adoptable Storage でのメタデータ暗号化に対して、dm-crypt
に基づくサポートが終了した実装と、dm-default-key
に基づく新しい実装の 2 つの実装があります。デバイスに適切な実装が選択されるようにするには、device.mk
の PRODUCT_SHIPPING_API_LEVEL
に正しい値を設定するようにします。たとえば、デバイスが Android 11(API レベル 30)で起動する場合、device.mk
に以下を含めます。
PRODUCT_SHIPPING_API_LEVEL := 30
次のようにシステム プロパティを設定して、出荷時の API レベルに関係なく、新しいボリューム メタデータ暗号化方式(および新しいデフォルトの FBE ポリシー バージョン)を使用するように強制することもできます。
PRODUCT_PROPERTY_OVERRIDES += \ ro.crypto.volume.metadata.method=dm-default-key \ ro.crypto.dm_default_key.options_format.version=2 \ ro.crypto.volume.options=::v2
現在の方法
Android 11 以降を搭載しているデバイスの場合、Adoptable Storage のメタデータ暗号化は、内部ストレージと同様、dm-default-key
カーネル モジュールを使用します。有効にするカーネル構成オプションについては、上記の前提条件をご覧ください。デバイスの内部ストレージ上で動作するインライン暗号化ハードウェアが Adoptable Storage 上では利用できない場合があり、そのため CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y
が必要になることがあります。
デフォルトでは、dm-default-key
ボリューム メタデータ暗号化方式は、AES-256-XTS 暗号化アルゴリズム(4096 バイトの暗号化セクター)を使用します。このアルゴリズムは、ro.crypto.volume.metadata.encryption
システム プロパティを設定することでオーバーライドできます。このプロパティの値の構文は、上記の metadata_encryption
fstab オプションと同じです。たとえば、AES アクセラレーションを搭載していないデバイスの場合、ro.crypto.volume.metadata.encryption=adiantum
を設定することで、Adiantum 暗号化を有効にできます。
以前の方法
Android 10 以前を搭載しているデバイスの場合、Adoptable Storage のメタデータ暗号化は、dm-default-key
ではなく、dm-crypt
カーネル モジュールを使用します。
CONFIG_DM_CRYPT=y
dm-default-key
メソッドと異なり、dm-crypt
メソッドの場合、ファイル コンテンツが 2 回暗号化されます(1 回目は FBE 鍵で、2 回目はメタデータ暗号鍵で暗号化されます)。この二重暗号化は、パフォーマンスを低下させるものである一方、メタデータ暗号化のセキュリティ目標を達成するうえで必須ではありません(FBE 鍵は少なくともメタデータ暗号鍵と同じようにサイバー攻撃に強いことが Android によって保証されています)。ベンダーは、カーネルをカスタマイズして、二重暗号化を回避できます。特に、allow_encrypt_override
オプションを実装する方法があります。このオプションは、ro.crypto.allow_encrypt_override
システム プロパティが true
に設定されている場合に、dm-crypt
に渡されます。
このようなカスタマイズは、Android 共通カーネルによってサポートされていません。
dm-crypt
ボリューム メタデータ暗号化方式は、デフォルトでは AES-128-CBC 暗号化アルゴリズム(ESSIV、512 バイトの暗号化セクター)を使用します。この設定は、以下のシステム プロパティを設定することでオーバーライドできます(FDE に対しても使用されます)。
ro.crypto.fde_algorithm
: メタデータ暗号化アルゴリズムを選択します。選択肢は、aes-128-cbc
、adiantum
です。Adiantum を使用できるのは、デバイスに AES アクセラレーションが搭載されていない場合に限られます。ro.crypto.fde_sector_size
: 暗号セクターのサイズを選択します。選択肢は、512、1024、2048、4096 です。Adiantum 暗号化の場合は、4096 を使用します。