メタデータ暗号化

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.rcon 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

メタデータ暗号化の有効化

最後に、userdatafstab エントリの 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.mkPRODUCT_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

デバイスの fstabmetadata_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 のいずれかの作業が直接的または間接的にブロックされると、デッドロックが発生します。voldinit の介入なしで、鍵の読み取り、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.mkPRODUCT_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-cbcadiantum です。Adiantum を使用できるのは、デバイスに AES アクセラレーションが搭載されていない場合に限られます。
  • ro.crypto.fde_sector_size: 暗号セクターのサイズを選択します。 選択肢は、512、1024、2048、4096 です。Adiantum 暗号化の場合は、4096 を使用します。