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 eitheraes-256-xts
oradiantum
. Since Android 11 it can also be left empty to specify the default algorithm, which isaes-256-xts
. - The
filenames_encryption_mode
parameter defines which cryptographic algorithm is used to encrypt file names. It can be eitheraes-256-cts
,aes-256-heh
,adiantum
, oraes-256-hctr2
. If not specified, it defaults toaes-256-cts
ifcontents_encryption_mode
isaes-256-xts
, or toadiantum
ifcontents_encryption_mode
isadiantum
. - 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; thev2
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 byro.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 toinlinecrypt_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, useinlinecrypt_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 theinlinecrypt
mount option, and either theinlinecrypt_optimized
oremmc_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.
- The
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 thefileencryption
fstab option, and it uses the same defaults. See the recommendations forfileencryption
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 ofro.crypto.volume.options
.ro.crypto.volume.filenames_mode
selects the filenames encryption mode. This is equivalent to the second colon-separated field ofro.crypto.volume.options
, except that the default on devices that launched with Android 10 or lower isaes-256-heh
. On most devices, this needs to be explicitly overridden toaes-256-cts
.ro.crypto.fde_algorithm
andro.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:
- Create a top-level directory (for example
misc_ne
) in theuserdata
partition. - Configure this top-level directory to be unencrypted (see Excluding directories).
- Create a directory within the top-level directory to hold OTA packages.
- 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
- Ensure
- Check that
ro.crypto.type
exists- Ensure
ro.crypto.type
is set tofile
- Ensure
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. |
|
System DE | Device-encrypted data not tied to a particular user |
|
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 |
|
User DE (internal) | Per-user device-encrypted data on internal storage |
|
User CE (adoptable) | Per-user credential-encrypted data on adoptable storage |
|
User DE (adoptable) | Per-user device-encrypted data on adoptable storage |
|
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.