File-based encryption

Android 7.0 and higher supports file-based encryption (FBE). File-based encryption allows different files to be encrypted with different keys that can be unlocked independently.

This article describes how to enable file-based encryption on new devices and how system apps can use the Direct Boot APIs to offer users the best, most secure experience possible.

All devices launching with Android 10 and higher are required to use file-based encryption.

Direct Boot

File-based encryption enables a new feature introduced in Android 7.0 called Direct Boot. Direct Boot allows encrypted devices to boot straight to the lock screen. Previously, on encrypted devices using full-disk encryption (FDE), users needed to provide credentials before any data could be accessed, preventing the phone from performing all but the most basic of operations. For example, alarms could not operate, accessibility services were unavailable, and phones could not receive calls but were limited to only basic emergency dialer operations.

With the introduction of file-based encryption (FBE) and new APIs to make apps aware of encryption, it is possible for these apps to operate within a limited context. This can happen before users have provided their credentials while still protecting private user information.

On an FBE-enabled device, each user of the device has two storage locations available to apps:

  • Credential Encrypted (CE) storage, which is the default storage location and only available after the user has unlocked the device.
  • Device Encrypted (DE) storage, which is a storage location available both during Direct Boot mode and after the user has unlocked the device.

This separation makes work profiles more secure because it allows more than one user to be protected at a time as the encryption is no longer based solely on a boot time password.

The Direct Boot API allows encryption-aware apps to access each of these areas. There are changes to the app lifecycle to accommodate the need to notify apps when a user's CE storage is unlocked in response to first entering credentials at the lock screen, or in the case of work profile providing a work challenge. Devices running Android 7.0 must support these new APIs and lifecycles regardless of whether or not they implement FBE. Although, without FBE, DE and CE storage are always in the unlocked state.

A complete implementation of file-based encryption on the Ext4 and F2FS file systems is provided in the Android Open Source Project (AOSP) and needs only be enabled on devices that meet the requirements. Manufacturers electing to use FBE can explore ways of optimizing the feature based on the system on chip (SoC) used.

All the necessary packages in AOSP have been updated to be direct-boot aware. However, where device manufacturers use customized versions of these apps, they want to ensure at a minimum there are direct-boot aware packages providing the following services:

  • Telephony Services and Dialer
  • Input method for entering passwords into the lock screen

Examples and source

Android provides a reference implementation of file-based encryption, in which vold (system/vold) provides the functionality for managing storage devices and volumes on Android. The addition of FBE provides vold with several new commands to support key management for the CE and DE keys of multiple users. In addition to the core changes to use the file-based encryption capabilities in the kernel, many system packages including the lockscreen and the SystemUI have been modified to support the FBE and Direct Boot features. These include:

  • AOSP Dialer (packages/apps/Dialer)
  • Desk Clock (packages/apps/DeskClock)
  • LatinIME (packages/inputmethods/LatinIME)*
  • Settings App (packages/apps/Settings)*
  • SystemUI (frameworks/base/packages/SystemUI)*

* System apps that use the defaultToDeviceProtectedStorage manifest attribute

More examples of apps and services that are encryption aware can be found by running the command mangrep directBootAware in the frameworks or packages directory of the AOSP source tree.

Dependencies

To use the AOSP implementation of FBE securely, a device needs to meet the following dependencies:

  • Kernel Support for Ext4 encryption or F2FS encryption.
  • Keymaster Support with HAL version 1.0 or higher. There is no support for Keymaster 0.3 as that does not provide the necessary capabilities or assure sufficient protection for encryption keys.
  • Keymaster/Keystore and Gatekeeper must be implemented in a Trusted Execution Environment (TEE) to provide protection for the DE keys so that an unauthorized OS (custom OS flashed onto the device) cannot simply request the DE keys.
  • Hardware Root of Trust and Verified Boot bound to the Keymaster initialization is required to ensure that DE keys are not accessible by an unauthorized operating system.

Implementation

First and foremost, apps such as alarm clocks, phone, and accessibility features should be made android:directBootAware according to the Direct Boot developer documentation.

Kernel support

Kernel support for Ext4 and F2FS encryption is available in the Android common kernels, version 3.18 and higher. To enable it in a kernel that is version 5.1 or higher, use:

CONFIG_FS_ENCRYPTION=y

For older kernels, use CONFIG_EXT4_ENCRYPTION=y if your device's userdata filesystem is Ext4, or use CONFIG_F2FS_FS_ENCRYPTION=y if your device's userdata filesystem is F2FS.

If your device supports adoptable storage or uses metadata encryption on internal storage, also enable the kernel configuration options needed for metadata encryption as described in the metadata encryption documentation.

In addition to functional support for Ext4 or F2FS encryption, device manufacturers should also enable cryptographic acceleration to speed up file-based encryption and improve the user experience. For example, on ARM64-based devices, ARMv8 CE (Cryptography Extensions) acceleration can be enabled by setting the following kernel configuration options:

CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y

To further improve performance and reduce power usage, device manufacturers might also consider implementing inline encryption hardware, which encrypts/decrypts the data while it is on the way to/from the storage device. The Android common kernels (version 4.14 and higher) contain a framework that allows inline encryption to be used when hardware and vendor driver support is available. The inline encryption framework can be enabled by setting the following kernel configuration options:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y

If your device uses UFS-based storage, also enable:

CONFIG_SCSI_UFS_CRYPTO=y

If your device uses eMMC-based storage, also enable:

CONFIG_MMC_CRYPTO=y

Enable file-based encryption

Enabling FBE on a device requires enabling it on the internal storage (userdata). This also automatically enables FBE on adoptable storage; however, the encryption format on adoptable storage can be overridden if necessary.

Internal storage

FBE is enabled by adding the option fileencryption=contents_encryption_mode[:filenames_encryption_mode[:flags]] to the fs_mgr_flags column of the fstab line for userdata. This option defines the encryption format on internal storage. It contains up to three colon-separated parameters:

  • The contents_encryption_mode parameter defines which cryptographic algorithm is used to encrypt file contents. It can be either aes-256-xts or adiantum. Since Android 11 it can also be left empty to specify the default algorithm, which is aes-256-xts.
  • The filenames_encryption_mode parameter defines which cryptographic algorithm is used to encrypt file names. It can be either aes-256-cts, aes-256-heh, adiantum, or aes-256-hctr2. If not specified, it defaults to aes-256-cts if contents_encryption_mode is aes-256-xts, or to adiantum if contents_encryption_mode is adiantum.
  • The flags parameter, new in Android 11, is a list of flags separated by the + character. The following flags are supported:
    • The v1 flag selects version 1 encryption policies; the v2 flag selects version 2 encryption policies. Version 2 encryption policies use a more secure and flexible key derivation function. The default is v2 if the device launched on Android 11 or higher (as determined by ro.product.first_api_level), or v1 if the device launched on Android 10 or lower.
    • The inlinecrypt_optimized flag selects an encryption format that is optimized for inline encryption hardware that doesn't handle large numbers of keys efficiently. It does this by deriving just one file contents encryption key per CE or DE key, rather than one per file. The generation of IVs (initialization vectors) is adjusted accordingly.
    • The emmc_optimized flag is similar to inlinecrypt_optimized, but it also selects an IV generation method that limits IVs to 32 bits. This flag should only be used on inline encryption hardware that is compliant with the JEDEC eMMC v5.2 specification and therefore supports only 32-bit IVs. On other inline encryption hardware, use inlinecrypt_optimized instead. This flag should never be used on UFS-based storage; the UFS specification allows the use of 64-bit IVs.
    • On devices that support hardware-wrapped keys, the wrappedkey_v0 flag enables the use of hardware-wrapped keys for FBE. This can only be used in combination with the inlinecrypt mount option, and either the inlinecrypt_optimized or emmc_optimized flag.
    • The dusize_4k flag forces the encryption data unit size to be 4096 bytes even when the filesystem block size is not 4096 bytes. The encryption data unit size is the granularity of file contents encryption. This flag is available since Android 15. This flag should only be used to enable the use of inline encryption hardware that does not support data units larger than 4096 bytes, on a device that uses a page size larger than 4096 bytes and that uses the f2fs filesystem.

If you aren't using inline encryption hardware the recommended setting for most devices is fileencryption=aes-256-xts. If you are using inline encryption hardware the recommended setting for most devices is fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized (or equivalently fileencryption=::inlinecrypt_optimized). On devices without any form of AES acceleration, Adiantum can be used instead of AES by setting fileencryption=adiantum.

Since Android 14, AES-HCTR2 is the preferred mode of filenames encryption for devices with accelerated cryptography instructions. However, only newer Android kernels support AES-HCTR2. In a future Android release, it is planned to become the default mode for filenames encryption. If your kernel has AES-HCTR2 support, it can be enabled for filenames encryption by setting filenames_encryption_mode to aes-256-hctr2. In the simplest case this would be done with fileencryption=aes-256-xts:aes-256-hctr2.

On devices that launched with Android 10 or lower, fileencryption=ice is also accepted to specify the use of the FSCRYPT_MODE_PRIVATE file contents encryption mode. This mode is unimplemented by the Android common kernels, but it could be implemented by vendors using custom kernel patches. The on-disk format produced by this mode was vendor-specific. On devices launching with Android 11 or higher, this mode is no longer allowed and a standard encryption format must be used instead.

By default, file contents encryption is done using the Linux kernel's cryptography API. If you want to use inline encryption hardware instead, also add the inlinecrypt mount option. For example, a full fstab line might look like:

/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

Since Android 9, FBE and adoptable storage can be used together.

Specifying the fileencryption fstab option for userdata also automatically enables both FBE and metadata encryption on adoptable storage. However, you can override the FBE or metadata encryption formats on adoptable storage by setting properties in PRODUCT_PROPERTY_OVERRIDES.

On devices that launched with Android 11 or higher, use the following properties:

  • ro.crypto.volume.options (new in Android 11) selects the FBE encryption format on adoptable storage. It has the same syntax as the argument to the fileencryption fstab option, and it uses the same defaults. See the recommendations for fileencryption above for what to use here.
  • ro.crypto.volume.metadata.encryption selects the metadata encryption format on adoptable storage. See the metadata encryption documentation.

On devices that launched with Android 10 or lower, use the following properties:

  • ro.crypto.volume.contents_mode selects the contents encryption mode. This is equivalent to the first colon-separated field of ro.crypto.volume.options.
  • ro.crypto.volume.filenames_mode selects the filenames encryption mode. This is equivalent to the second colon-separated field of ro.crypto.volume.options, except that the default on devices that launched with Android 10 or lower is aes-256-heh. On most devices, this needs to be explicitly overridden to aes-256-cts.
  • ro.crypto.fde_algorithm and ro.crypto.fde_sector_size select the metadata encryption format on adoptable storage. See the metadata encryption documentation.

Integrate with Keymaster

The Keymaster HAL should be started as part of the early_hal class. This is because FBE requires that Keymaster be ready to handle requests by the post-fs-data boot phase, which is when vold sets up the initial keys.

Exclude directories

init applies the system DE key to all top-level directories of /data, except for directories that must be unencrypted such as the directory that contains the system DE key itself and directories that contain user CE or DE directories. Encryption keys apply recursively and cannot be overridden by subdirectories.

In Android 11 and higher, the key that init applies to directories can be controlled by the encryption=<action> argument to the mkdir command in init scripts. The possible values of <action> are documented in the README for the Android init language.

In Android 10, the init encryption actions were hardcoded into the following location:

/system/extras/libfscrypt/fscrypt_init_extensions.cpp

In Android 9 and earlier, the location was:

/system/extras/ext4_utils/ext4_crypt_init_extensions.cpp

It is possible to add exceptions to prevent certain directories from being encrypted at all. If modifications of this sort are made then the device manufacturer should include SELinux policies that only grant access to the apps that need to use the unencrypted directory. This should exclude all untrusted apps.

The only known acceptable use case for this is in support of legacy OTA capabilities.

Support Direct Boot in system apps

Make apps Direct Boot aware

To facilitate rapid migration of system apps, there are two new attributes that can be set at the app level. The defaultToDeviceProtectedStorage attribute is available only to system apps. The directBootAware attribute is available to all.

<application
    android:directBootAware="true"
    android:defaultToDeviceProtectedStorage="true">

The directBootAware attribute at the app level is shorthand for marking all components in the app as being encryption aware.

The defaultToDeviceProtectedStorage attribute redirects the default app storage location to point at DE storage instead of pointing at CE storage. System apps using this flag must carefully audit all data stored in the default location, and change the paths of sensitive data to use CE storage. Device manufactures using this option should carefully inspect the data that they are storing to ensure that it contains no personal information.

When running in this mode, the following System APIs are available to explicitly manage a Context backed by CE storage when needed, which are equivalent to their Device Protected counterparts.

  • Context.createCredentialProtectedStorageContext()
  • Context.isCredentialProtectedStorage()

Support multiple users

Each user in a multi-user environment gets a separate encryption key. Every user gets two keys: a DE and a CE key. User 0 must log into the device first as it is a special user. This is pertinent for Device Administration uses.

Crypto-aware apps interact across users in this manner: INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL allow an app to act across all the users on the device. However, those apps can access only CE-encrypted directories for users that are already unlocked.

An app might be able to interact freely across the DE areas, but one user unlocked does not mean that all the users on the device are unlocked. The app should check this status before trying to access these areas.

Each work profile user ID also gets two keys: DE and CE. When the work challenge is met, the profile user is unlocked and the Keymaster (in TEE) can provide the profile's TEE key.

Handle updates

The recovery partition is unable to access the DE-protected storage on the userdata partition. Devices implementing FBE are strongly recommended to support OTA using A/B system updates. As the OTA can be applied during normal operation there is no need for recovery to access data on the encrypted drive.

When using a legacy OTA solution, which requires recovery to access the OTA file on the userdata partition:

  1. Create a top-level directory (for example misc_ne) in the userdata partition.
  2. Configure this top-level directory to be unencrypted (see Excluding directories).
  3. Create a directory within the top-level directory to hold OTA packages.
  4. Add an SELinux rule and file contexts to control access to this directory and it contents. Only the process or apps receiving OTA updates should be able to read and write to this directory. No other app or process should have access to this directory.

Validation

To ensure the implemented version of the feature works as intended, first run the many CTS encryption tests, such as DirectBootHostTest and EncryptionTest.

If the device is running Android 11 or higher, also run vts_kernel_encryption_test:

atest vts_kernel_encryption_test

or:

vts-tradefed run vts -m vts_kernel_encryption_test

In addition, device manufacturers can perform the following manual tests. On a device with FBE enabled:

  • Check that ro.crypto.state exists
    • Ensure ro.crypto.state is encrypted
  • Check that ro.crypto.type exists
    • Ensure ro.crypto.type is set to file

Additionally, testers can verify that CE storage is locked before the device has been unlocked for the first time since boot. To do this, use a userdebug or eng build, set a PIN, pattern, or password on the main user, and reboot the device. Before unlocking the device, run the following command to check the CE storage of the main user. If the device uses Headless System User Mode (most Automotive devices), the main user is user 10, so run:

adb root; adb shell ls /data/user/10

On other devices (most non-Automotive devices), the main user is user 0, so run:

adb root; adb shell ls /data/user/0

Verify that the listed filenames are Base64-encoded, indicating that the filenames are encrypted and the key to decrypt them is not yet available. If the filenames are listed in plaintext, something is wrong.

Device manufacturers are also encouraged to explore running the upstream Linux tests for fscrypt on their devices or kernels. These tests are part of the xfstests filesystem test suite. However, these upstream tests are not offically supported by Android.

AOSP implementation details

This section provides details on the AOSP implementation and describes how file-based encryption works. It should not be necessary for device manufacturers to make any changes here to use FBE and Direct Boot on their devices.

fscrypt encryption

The AOSP implementation uses "fscrypt" encryption (supported by ext4 and f2fs) in the kernel and normally is configured to:

  • Encrypt file contents with AES-256 in XTS mode
  • Encrypt file names with AES-256 in CBC-CTS mode

Adiantum encryption is also supported. When Adiantum encryption is enabled, both file contents and file names are encrypted with Adiantum.

fscrypt supports two versions of encryption policies: version 1 and version 2. Version 1 is deprecated, and the CDD requirements for devices launching with Android 11 and higher are only compatible with version 2. Version 2 encryption policies use HKDF-SHA512 to derive the actual encryption keys from the userspace-supplied keys.

For more information about fscrypt, see the upstream kernel documentation.

Storage classes

The following table lists the FBE keys and the directories they protect in more detail:

Storage class Description Directories
Unencrypted Directories in /data that can't be or don't need to be protected by FBE. On devices that use metadata encryption, these directories aren't truly unencrypted but rather are protected by the metadata encryption key which is equivalent to System DE.
  • /data/apex, excluding /data/apex/decompressed and /data/apex/ota_reserved which are system DE
  • /data/lost+found
  • /data/preloads
  • /data/unencrypted
  • All directories whose subdirectories use different FBE keys. For example, since each /data/user/${user_id} directory uses a per-user key, /data/user uses no key itself.
System DE Device-encrypted data not tied to a particular user
  • /data/apex/decompressed
  • /data/apex/ota_reserved
  • /data/app
  • /data/misc
  • /data/system
  • /data/vendor
  • All other subdirectories of /data that this table doesn't mention as having a different class
Per-boot Ephemeral system files that don't need to survive a reboot /data/per_boot
User CE (internal) Per-user credential-encrypted data on internal storage
  • /data/data (alias of /data/user/0)
  • /data/media/${user_id}
  • /data/misc_ce/${user_id}
  • /data/system_ce/${user_id}
  • /data/user/${user_id}
  • /data/vendor_ce/${user_id}
User DE (internal) Per-user device-encrypted data on internal storage
  • /data/misc_de/${user_id}
  • /data/system_de/${user_id}
  • /data/user_de/${user_id}
  • /data/vendor_de/${user_id}
User CE (adoptable) Per-user credential-encrypted data on adoptable storage
  • /mnt/expand/${volume_uuid}/media/${user_id}
  • /mnt/expand/${volume_uuid}/misc_ce/${user_id}
  • /mnt/expand/${volume_uuid}/user/${user_id}
User DE (adoptable) Per-user device-encrypted data on adoptable storage
  • /mnt/expand/${volume_uuid}/misc_de/${user_id}
  • /mnt/expand/${volume_uuid}/user_de/${user_id}

Key storage and protection

All FBE keys are managed by vold and are stored encrypted on-disk, except for the per-boot key which is not stored at all. The following table lists the locations in which the various FBE keys are stored:

Key type Key location Storage class of key location
System DE key /data/unencrypted Unencrypted
User CE (internal) keys /data/misc/vold/user_keys/ce/${user_id} System DE
User DE (internal) keys /data/misc/vold/user_keys/de/${user_id} System DE
User CE (adoptable) keys /data/misc_ce/${user_id}/vold/volume_keys/${volume_uuid} User CE (internal)
User DE (adoptable) keys /data/misc_de/${user_id}/vold/volume_keys/${volume_uuid} User DE (internal)

As shown in the preceding table, most FBE keys are stored in directories that are encrypted by another FBE key. Keys cannot be unlocked until the storage class that contains them has been unlocked.

vold also applies a layer of encryption to all FBE keys. Every key besides CE keys for internal storage is encrypted with AES-256-GCM using its own Keystore key that is not exposed outside the TEE. This ensures that FBE keys cannot be unlocked unless a trusted operating system has booted, as enforced by Verified Boot. Rollback resistance is also requested on the Keystore key, which allows FBE keys to be securely deleted on devices where Keymaster supports rollback resistance. As a best-effort fallback for when rollback resistance is unavailable, the SHA-512 hash of 16384 random bytes stored in the secdiscardable file stored alongside the key is used as the app ID tag of the Keystore key. All these bytes need to be recovered to recover an FBE key.

CE keys for internal storage receive a stronger level of protection that ensures they cannot be unlocked without knowing either the user's Lock Screen Knowledge Factor (LSKF) (PIN, pattern, or password), a secure passcode reset token, or both the client-side and server-side keys for a Resume-on-Reboot operation. Passcode reset tokens are only allowed to be created for work profiles and fully managed devices.

To achieve this, vold encrypts each CE key for internal storage using an AES-256-GCM key derived from the user's synthetic password. The synthetic password is an immutable high-entropy cryptographic secret that is randomly generated for each user. LockSettingsService in system_server manages the synthetic password and the ways in which it is protected.

To protect the synthetic password with the LSKF, LockSettingsService first stretches the LSKF by passing it through scrypt, targeting a time of about 25 ms and a memory usage of about 2 MiB. Since LSKFs are usually short, this step usually does not provide much security. The main layer of security is the Secure Element (SE) or TEE-enforced ratelimiting described below.

If the device has a Secure Element (SE), then LockSettingsService maps the stretched LSKF to a high-entropy random secret stored in the SE using the Weaver HAL. LockSettingsService then encrypts the synthetic password twice: first with a software key derived from the stretched LSKF and the Weaver secret, and second with a non-auth-bound Keystore key. This provides SE-enforced ratelimiting of LSKF guesses.

If the device doesn't have a SE, then LockSettingsService instead uses the stretched LSKF as a Gatekeeper password. LockSettingsService then encrypts the synthetic password twice: first with a software key derived from the stretched LSKF and the hash of a secdiscardable file, and second with a Keystore key that is auth-bound to the Gatekeeper enrollment. This provides TEE-enforced ratelimiting of LSKF guesses.

When the LSKF is changed, LockSettingsService deletes all information associated with the binding of the synthetic password to the old LSKF. On devices that support Weaver or rollback resistant Keystore keys, this guarantees secure deletion of the old binding. For this reason, the protections described here are applied even when the user does not have an LSKF.