Android Storage Encryption
Security and user privacy are paramount in Android. Encryption ensures that even if a device is physically compromised and the storage chip is desoldered and read directly, the data remains unintelligible without the user's credentials.
Modern Android (Android 7.0+) uses File-Based Encryption (FBE), which replaced the older Full-Disk Encryption (FDE).
File-Based Encryption (FBE)
Under Full-Disk Encryption, the entire /data partition was encrypted with a single key. The device could not boot past the bootloader without the user's PIN/Password, meaning alarms wouldn't ring and phone calls couldn't be received until the device was unlocked.
File-Based Encryption solves this by encrypting different files with different keys. This enables Direct Boot, allowing the device to boot to the lock screen and run essential background services before the user enters their credentials.
Android defines two primary storage locations for apps under FBE:
- Device Encrypted (DE) Storage: Available immediately after the device boots. Used for critical apps like Phone, Alarm, and system services. Keys are tied to the hardware and the Verified Boot state.
- Credential Encrypted (CE) Storage: Available only after the user unlocks the device with their PIN, pattern, or password. Used for the vast majority of app data. Keys are tied to both the hardware and the user's credentials.
fscrypt Kernel Integration
Android implements FBE using the fscrypt subsystem built into the Linux kernel. fscrypt provides native file encryption support for filesystems like EXT4 and F2FS.
Instead of encrypting block by block in an opaque layer (like dm-crypt used in FDE), fscrypt encrypts the file contents and the file names natively within the filesystem.
When vold sets up a directory for a user, it uses ioctl commands to apply an encryption policy to that directory.
// Simplified kernel interaction pseudo-code used by vold
struct fscrypt_policy_v2 policy;
policy.version = FSCRYPT_POLICY_V2;
policy.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
policy.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
memcpy(policy.master_key_descriptor, key_ref, FSCRYPT_KEY_DESCRIPTOR_SIZE);
ioctl(dir_fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy);
Once a policy is applied to a directory, all newly created files and subdirectories inherit this policy and are automatically encrypted by the kernel before being written to flash storage.
Key Derivation for CE and DE
Key management is highly secure and relies on the hardware-backed Keymaster or KeyMint HAL.
- Hardware Root of Trust: The process starts with a Hardware Bound Key (HBK) embedded in the Secure Element (SE) or Trusted Execution Environment (TEE).
- Weaver/Gatekeeper: The user's PIN/password is passed to the Gatekeeper HAL. It is hashed and run through a rate-limiting mechanism (Weaver) inside the secure hardware to prevent brute-force attacks.
- Key Derivation: The output from Gatekeeper, combined with the hardware root key, is used to derive the actual CE key. The DE key is derived without the user's PIN.
- Installing Keys:
voldinstalls these derived keys into the kernel keyring sofscryptcan use them. When the screen is locked, the CE key can be evicted from memory (depending on configuration), making the CE storage inaccessible until unlocked again.
Metadata Encryption
While FBE encrypts file contents and names, filesystem metadata (like file sizes, permissions, and directory structures) remains unencrypted. To mitigate information leakage, Android introduced Metadata Encryption.
Metadata encryption uses dm-default-key (a device mapper target in the kernel) to encrypt the entire /data partition blocks containing metadata with a key generated at boot (and bound to the hardware). It works alongside FBE, providing a dual-layer defense.
Practical Commands
Checking encryption status:
adb shell getprop ro.crypto.state
Viewing FBE policies via dumpsys:
adb shell dumpsys vold | grep -i fbe