Google is committed to advancing racial equity for Black communities. See how.

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 applications can use the Direct Boot APIs to offer users the best, most secure experience possible.

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 applications 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 applications:

  • 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 applications to access each of these areas. There are changes to the application lifecycle to accommodate the need to notify applications 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 will always be 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 may wish to 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 will 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 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 applications that use the defaultToDeviceProtectedStorage manifest attribute

More examples of applications 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 a HAL version 1.0 or 2.0. There is no support for Keymaster 0.3 as that does not provide that 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 initialisation is required to ensure that Device Encryption credentials are not accessible by an unauthorized operating system.

Note: Storage policies are applied to a folder and all of its subfolders. Manufacturers should limit the contents that go unencrypted to the OTA folder and the folder that holds the key that decrypts the system. Most contents should reside in credential-encrypted storage rather than device-encrypted storage.

Implementation

First and foremost, apps such as alarm clocks, phone, accessibility features should be made android:directBootAware according to 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 will support adoptable storage or will use 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 may 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

Enabling 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 may 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.
  • 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, or adiantum. 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 R, 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 R 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.
    • The wrappedkey_v0 flag enables the use of hardware-wrapped keys. When enabled, FBE keys are not generated by software, but rather are generated by Keymaster using the STORAGE_KEY tag. Then, each FBE key actually provided to the kernel is the STORAGE_KEY key exported from Keymaster, which causes it to be wrapped with a per-boot ephemeral key. The kernel then provides the wrapped keys directly to the inline encryption hardware. When implemented correctly, the unwrapped keys are never present in system memory, and a compromised wrapped key cannot be used after a reboot. This flag requires hardware support, Keymaster support for STORAGE_KEY, kernel driver support, the inlinecrypt mount option, and either the inlinecrypt_optimized or emmc_optimized flags.

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. On devices without any form of AES acceleration, Adiantum may be used instead of AES by setting fileencryption=adiantum.

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 R 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 may override the FBE and/or metadata encryption formats on adoptable storage by setting properties in PRODUCT_PROPERTY_OVERRIDES.

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

  • ro.crypto.volume.options (new in Android R) 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.

Integrating with Keymaster

The generation of keys and management of the kernel keyring is handled by vold. The AOSP implementation of FBE requires that the device support Keymaster HAL version 1.0 or later. There is no support for earlier versions of the Keymaster HAL.

On first boot, user 0’s keys are generated and installed early in the boot process. By the time the on-post-fs phase of init completes, the Keymaster must be ready to handle requests. On Pixel devices, this is handled by having a script block ensure Keymaster is started before /data is mounted.

Encryption policy

File-based encryption applies the encryption policy at the directory level. When a device’s userdata partition is first created, the basic structures and policies are applied by the init scripts. These scripts will trigger the creation of the first user’s (user 0’s) CE and DE keys as well as define which directories are to be encrypted with these keys. When additional users and profiles are created, the necessary additional keys are generated and stored in the keystore; their credential and devices storage locations are created and the encryption policy links these keys to those directories.

In Android R and higher, the encryption policy is no longer hardcoded into a centralized location, but rather is defined by arguments to the mkdir commands in the init scripts. Directories encrypted with the system DE key use encryption=Require, while unencrypted directories (or directories whose subdirectories are encrypted with per-user keys) use encryption=None.

In Android 10, the encryption policy was hardcoded into this 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 applications that need to use the unencrypted directory. This should exclude all untrusted applications.

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

Supporting Direct Boot in system applications

Making applications Direct Boot aware

To facilitate rapid migration of system apps, there are two new attributes that can be set at the application 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 application 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()

Supporting 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 applications interact across users in this manner: INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL allow an application to act across all the users on the device. However, those apps will be able to access only CE-encrypted directories for users that are already unlocked.

An application may 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 application 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.

Handling 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. Add this top-level directory to the encryption policy exception (see Encryption policy above).
  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 folder and it contents. Only the process or applications receiving OTA updates should be able to read and write to this folder. No other application or process should have access to this folder.

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 R 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 may 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 boot a userdebug instance with a lockscreen set on the primary user. Then adb shell into the device and use su to become root. Make sure /data/data contains encrypted filenames; if it does not, 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.

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

Key derivation

File-based encryption keys, which are 512-bit keys, are stored encrypted by another key (a 256-bit AES-GCM key) held in the TEE. To use this TEE key, three requirements must be met:

  • The auth token
  • The stretched credential
  • The “secdiscardable hash”

The auth token is a cryptographically authenticated token generated by Gatekeeper when a user successfully logs in. The TEE will refuse to use the key unless the correct auth token is supplied. If the user has no credential, then no auth token is used nor needed.

The stretched credential is the user credential after salting and stretching with the scrypt algorithm. The credential is actually hashed once in the lock settings service before being passed to vold for passing to scrypt. This is cryptographically bound to the key in the TEE with all the guarantees that apply to KM_TAG_APPLICATION_ID. If the user has no credential, then no stretched credential is used nor needed.

The secdiscardable hash is a 512-bit hash of a random 16 KB file stored alongside other information used to reconstruct the key, such as the seed. This file is securely deleted when the key is deleted, or it is encrypted in a new way; this added protection ensures an attacker must recover every bit of this securely deleted file to recover the key. This is cryptographically bound to the key in the TEE with all the guarantees that apply to KM_TAG_APPLICATION_ID.

In most cases, FBE keys also undergo an additional key derivation step in the kernel in order to generate the subkeys actually used to do the encryption, for example per-file or per-mode keys. For version 2 encryption policies, HKDF-SHA512 is used for this.