Full-Disk Encryption | Android Open Source Project
Android 9 or lower can use full-disk encryption. Devices that launched with
Android 10 or higher must use
file-based encryption instead. Android 10-12 support full-disk encryption
only for devices that upgraded from a lower Android version. Android T (AOSP experimental) removes support for full-disk encryption entirely.
Full-disk encoding is the process of encoding all user data on an Android device using an code samara. Once a device is encrypted, all user-created data is mechanically encrypted before committing it to disk and all reads automatically decrypt data before returning it to the calling serve .
Full-disk encoding was introduced to Android in 4.4, but Android 5.0 introduced these newly features :
- Created fast encryption, which only encrypts used blocks on the data partition
to avoid first boot taking a long time. Only ext4 and f2fs filesystems
currently support fast encryption. - Added the
forceencrypt
fstab flag to encrypt on first boot. - Added support for patterns and encryption without a password.
- Added hardware-backed storage of the encryption key using Trusted
Execution Environment’s (TEE) signing capability (such as in a TrustZone).
See Storing the encrypted key for more
details.
Caution: Devices upgraded to Android 5.0 and then encrypted may be returned to an unencrypted submit by factory data readjust. New Android 5.0 devices encrypted at first boot can not be returned to an unencrypted state .
How Android full-disk encryption works
Android full-disk encoding is based on dm-crypt
, which is a kernel sport that works at the block device layer. Because of this, encoding works with Embedded MultiMediaCard ( eMMC ) and similar flash devices that present themselves to the kernel as parry devices. encoding is not potential with YAFFS, which talks directly to a raw NAND brassy nick.
The encoding algorithm is 128 Advanced Encryption Standard ( AES ) with cipher-block chain ( CBC ) and ESSIV : SHA256. The victor key is encrypted with 128-bit AES via calls to the OpenSSL library. You must use 128 bits or more for the key ( with 256 being optional ) .
Note: OEMs can use 128-bit or higher to encrypt the master key .
In the Android 5.0 release, there are four kinds of encoding states :
- default
- PIN
- password
- pattern
Upon beginning kick, the device creates a randomly generated 128-bit master key and then hashes it with a default password and stored salt. The default option password is : “ default_password ” however, the attendant hash is besides signed through a TEE ( such as TrustZone ), which uses a hashish of the signature to encrypt the master key .
You can find the default password defined in the Android Open Source Project cryptfs.cpp file .
When the drug user sets the PIN/pass or password on the device, alone the 128-bit key is re-encrypted and stored. ( i. exploiter PIN/pass/pattern changes do NOT cause re-encryption of userdata. ) Note that managed device may be subjugate to PIN, pattern, or password restrictions .
encoding is managed by init
and vold
. init
calls vold
, and vold sets properties to trigger events in init. other parts of the system besides look at the properties to conduct tasks such as composition condition, ask for a password, or prompt to factory reset in the case of a fatal error. To invoke encoding features in vold
, the system uses the command line tool vdc
’ s cryptfs
commands : checkpw
, restart
, enablecrypto
, changepw
, cryptocomplete
, verifypw
, setfield
, getfield
, mountdefaultencrypted
, getpwtype
, getpw
, and clearpw
.
In order to encrypt, decode or wipe /data
, /data
must not be mounted. however, in arrange to show any drug user interface ( UI ), the framework must start and the framework requires /data
to run. To resolve this riddle, a irregular filesystem is mounted on /data
. This allows Android to prompt for passwords, show progress, or suggest a datum rub as needed. It does impose the limitation that in order to switch from the temp filesystem to the true /data
filesystem, the system must stop every process with open files on the irregular filesystem and restart those processes on the very /data
filesystem. To do this, all services must be in one of three groups : core
, main
, and late_start
.
core
: Never shut down after starting.main
: Shut down and then restart after the disk password is entered.late_start
: Does not start until after/data
has been decrypted and mounted.
To trigger these actions, the vold.decrypt
property is set to assorted strings. To kill and restart services, the init
commands are :
class_reset
: Stops a service but allows it to be restarted with class_start.class_start
: Restarts a service.class_stop
: Stops a service and adds aSVC_DISABLED
flag.
Stopped services do not respond toclass_start
.
Flows
There are four flows for an code device. A device is encrypted just once and then follows a normal boot flow .
- Encrypt a previously unencrypted device:
- Encrypt a new device with
forceencrypt
: Mandatory encryption
at first boot (starting in Android L). - Encrypt an existing device: User-initiated encryption (Android K and earlier).
- Encrypt a new device with
- Boot an encrypted device:
- Starting an encrypted device with no password: Booting an encrypted device that
has no set password (relevant for devices running Android 5.0 and later). - Starting an encrypted device with a password: Booting an encrypted device that
has a set password.
- Starting an encrypted device with no password: Booting an encrypted device that
In accession to these flows, the device can besides fail to encrypt /data
. Each of the flows are explained in detail below .
Encrypt a new device with forceencrypt
This is the normal beginning bang for an Android 5.0 device .
- Detect unencrypted filesystem with
forceencrypt
flag
/data
is not encrypted but needs to be becauseforceencrypt
mandates it. Unmount/data
. - Start encrypting
/data
vold.decrypt = "trigger_encryption"
triggersinit.rc
, which will causevold
to encrypt/data
with no password. ( none is set because this should be a new device. ) - Mount tmpfs
vold
mounts a tmpfs/data
( using the tmpfs options fromro.crypto.tmpfs_options
) and sets the propertyvold.encrypt_progress
to 0.vold
prepepares the tmpfs/data
for booting an code organization and sets the propertyvold.decrypt
to :trigger_restart_min_framework
- Bring up framework to show progress
Because the device has about no datum to encrypt, the progress bar will frequently not actually appear because encoding happens then cursorily. See Encrypt an existing device for more details about the progress UI . - When
/data
is encrypted, take down the framework
vold
setsvold.decrypt
totrigger_default_encryption
which starts thedefaultcrypto
serve. ( This starts the flow below for mounting a default option encrypted userdata. )trigger_default_encryption
checks the encoding type to see if/data
is encrypted with or without a password. Because Android 5.0 devices are encrypted on beginning boot, there should be no password set ; therefore we decrypt and mount/data
. - Mount
/data
init
then mounts/data
on a tmpfs RAMDisk using parameters it picks up fromro.crypto.tmpfs_options
, which is set ininit.rc
. - Start framework
Setvold
totrigger_restart_framework
, which continues the common boot process .
Encrypt an existing device
This is what happens when you encrypt an unencrypted Android K or earlier device that has been migrated to L .
This march is user-initiated and is referred to as “ inplace encoding ” in the code. When a user selects to encrypt a device, the UI makes surely the battery is in full charged and the AC adapter is plugged in thus there is enough might to finish the encoding action .
Warning: If the device runs out of exponent and shuts down before it has finished encrypting, file data is left in a partially encrypted state. The device must be factory reset and all data is lost .
To enable inplace encoding, vold
starts a loop to read each sector of the real parry device and then write it to the crypto engine block device. vold
checks to see if a sector is in use before reading and writing it, which makes encoding much faster on a new device that has little to no data .
State of device : Set ro.crypto.state = "unencrypted"
and execute the on nonencrypted
init
gun trigger to continue boot .
- Check password
The UI callsvold
with the commandcryptfs enablecrypto inplace
wherepasswd
is the exploiter ‘s lock screen password . - Take down the framework
vold
checks for errors, returns -1 if it ca n’t encrypt, and prints a argue in the log. If it can encrypt, it sets the propertyvold.decrypt
totrigger_shutdown_framework
. This causesinit.rc
to stop services in the classeslate_start
andmain
. - Create a crypto footer
- Create a breadcrumb file
- Reboot
- Detect breadcrumb file
- Start encrypting
/data
vold
then sets up the crypto mapping, which creates a virtual crypto block device that maps onto the real block device but encrypts each sector as it is written, and decrypts each sector as it is read.vold
then creates and writes out the crypto metadata . - While it’s encrypting, mount tmpfs
vold
mounts a tmpfs/data
( using the tmpfs options fromro.crypto.tmpfs_options
) and sets the propertyvold.encrypt_progress
to 0.vold
prepares the tmpfs/data
for booting an code arrangement and sets the propertyvold.decrypt
to :trigger_restart_min_framework
- Bring up framework to show progress
trigger_restart_min_framework
causesinit.rc
to start themain
class of services. When the framework sees thatvold.encrypt_progress
is set to 0, it brings up the progress banish UI, which queries that property every five seconds and updates a progress bar. The encoding loop updatesvold.encrypt_progress
every fourth dimension it encrypts another percentage of the partition . - When
/data
is encrypted, update the crypto footer
When/data
is successfully encrypted,vold
clears the irisENCRYPTION_IN_PROGRESS
in the metadata .
When the device is successfully unlock, the password is then used to encrypt the overcome key and the crypto footnote is updated .
If the boot fails for some reason,vold
sets the propertyvold.encrypt_progress
toerror_reboot_failed
and the UI should display a message asking the drug user to press a button to reboot. This is not expected to ever occur .
Starting an encrypted device with default encryption
This is what happens when you boot up an code device with no password. Because Android 5.0 devices are encrypted on first kick, there should be no fix password and therefore this is the default encoding state .
- Detect encrypted
/data
with no password
detect that the Android device is encrypted because/data
can not be mounted and one of the flagsencryptable
orforceencrypt
is set .
vold
setsvold.decrypt
totrigger_default_encryption
, which starts thedefaultcrypto
serve.trigger_default_encryption
checks the encoding type to see if/data
is encrypted with or without a password . - Decrypt /data
Creates thedm-crypt
device over the block device so the device is quick for consumption . - Mount /data
vold
then mounts the decode very/data
division and then prepares the new partition. It sets the propertyvold.post_fs_data_done
to 0 and then setsvold.decrypt
totrigger_post_fs_data
. This causesinit.rc
to run itspost-fs-data
commands. They will create any necessity directories or links and then setvold.post_fs_data_done
to 1 .
oncevold
sees the 1 in that property, it sets the propertyvold.decrypt
to :trigger_restart_framework.
This causesinit.rc
to start services in classmain
again and besides start services in classifylate_start
for the foremost time since boot . - Start framework
now the model boots all its services using the decode/data
, and the system is fix for use .
Starting an encrypted device without default encryption
This is what happens when you boot up an code device that has a set password. The device ’ s password can be a bowling pin, traffic pattern, or password .
- Detect encrypted device with a password
detect that the Android device is encrypted because the ease upro.crypto.state = "encrypted"
vold
setsvold.decrypt
totrigger_restart_min_framework
because/data
is encrypted with a password . - Mount tmpfs
init
sets five properties to save the initial climb options given for/data
with parameters passed frominit.rc
.vold
uses these properties to set up the crypto map :ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(ASCII 8-digit hex number preceded by 0x)
- Start framework to prompt for password
The framework starts up and sees thatvold.decrypt
is set totrigger_restart_min_framework
. This tells the framework that it is booting on a tmpfs/data
phonograph record and it needs to get the drug user password .
first, however, it needs to make certain that the disk was properly encrypted. It sends the commandcryptfs cryptocomplete
tovold
.vold
returns 0 if encoding was completed successfully, -1 on inner error, or -2 if encoding was not completed successfully.vold
determines this by looking in the crypto metadata for theCRYPTO_ENCRYPTION_IN_PROGRESS
flag. If it ‘s set, the encoding process was interrupted, and there is no functional data on the device. Ifvold
returns an error, the UI should display a message to the user to reboot and factory reset the device, and give the user a button to press to do so . - Decrypt data with password
oncecryptfs cryptocomplete
is successful, the model displays a UI asking for the disk password. The UI checks the password by sending the commandcryptfs checkpw
tovold
. If the password is compensate ( which is determined by successfully mounting the decode/data
at a impermanent placement, then unmounting it ),vold
saves the mention of the decode obstruct device in the propertyro.crypto.fs_crypto_blkdev
and returns status 0 to the UI. If the password is incorrect, it returns -1 to the UI . - Stop framework
The UI puts up a crypto boot graphic and then callsvold
with the commandcryptfs restart
.vold
sets the propertyvold.decrypt
totrigger_reset_main
, which causesinit.rc
to doclass_reset main
. This stops all services in the main class, which allows the tmpfs/data
to be unmounted . - Mount
/data
vold
then mounts the decode real/data
division and prepares the modern partition ( which may never have been prepared if it was encrypted with the rub option, which is not supported on first release ). It sets the placevold.post_fs_data_done
to 0 and then setsvold.decrypt
totrigger_post_fs_data
. This causesinit.rc
to run itspost-fs-data
commands. They will create any necessary directories or links and then setvold.post_fs_data_done
to 1. oncevold
sees the 1 in that property, it sets the placevold.decrypt
totrigger_restart_framework
. This causesinit.rc
to start services in coursemain
again and besides start services in classlate_start
for the first time since boot . - Start full framework
immediately the framework boots all its services using the decode/data
filesystem, and the system is fix for use .
Failure
A device that fails to decrypt might be awry for a few reasons. The device starts with the normal series of steps to boot :
- Detect encrypted device with a password
- Mount tmpfs
- Start framework to prompt for password
But after the model opens, the device can encounter some errors :
- Password matches but cannot decrypt data
- User enters wrong password 30 times
If these errors are not resolved, prompt user to factory wipe :
If vold
detects an error during the encoding action, and if no datum has been destroyed even and the model is up, vold
sets the property vold.encrypt_progress
to error_not_encrypted
. The UI prompts the drug user to reboot and alerts them the encoding process never started. If the error occurs after the model has been torn down, but before the progress bar UI is up, vold
will reboot the system. If the boot fails, it sets vold.encrypt_progress
to error_shutting_down
and returns -1 ; but there will not be anything to catch the error. This is not expected to happen .
If vold
detects an error during the encoding process, it sets vold.encrypt_progress
to error_partially_encrypted
and returns -1. The UI should then display a message saying the encoding failed and provide a button for the user to factory reset the device .
Storing the encrypted key
The code keystone is stored in the crypto metadata. Hardware back is implemented by using Trusted Execution Environment ’ randomness ( TEE ) sign capability. previously, we encrypted the dominate key with a key generated by applying scrypt to the exploiter ‘s password and the store salt. In order to make the key resilient against off-box attacks, we extend this algorithm by signing the result winder with a store TEE samara. The vector sum touch is then turned into an allow duration key by one more application of scrypt. This key is then used to encrypt and decrypt the overlord key. To store this key :
Read more: A Few Thoughts on Cryptographic Engineering
- Generate random 16-byte disk encryption key (DEK) and 16-byte salt.
- Apply scrypt to the user password and the salt to produce 32-byte intermediate
key 1 (IK1). - Pad IK1 with zero bytes to the size of the hardware-bound private key (HBK).
Specifically, we pad as: 00 || IK1 || 00..00; one zero byte, 32 IK1 bytes, 223
zero bytes. - Sign padded IK1 with HBK to produce 256-byte IK2.
- Apply scrypt to IK2 and salt (same salt as step 2) to produce 32-byte IK3.
- Use the first 16 bytes of IK3 as KEK and the last 16 bytes as IV.
- Encrypt DEK with AES_CBC, with key KEK, and initialization vector IV.
Changing the password
When a exploiter elects to change or remove their password in settings, the UI sends the control cryptfs changepw
to vold
, and vold
re-encrypts the harrow master key with the new password .
Encryption properties
vold
and init
communicate with each early by setting properties. here is a list of available properties for encoding .
Vold properties
Property | Description |
---|---|
vold.decrypt trigger_encryption |
Encrypt the drive with no password. |
vold.decrypt trigger_default_encryption |
Check the drive to see if it is encrypted with no password. If it is, decrypt and mount it, else set vold.decrypt to trigger_restart_min_framework. |
vold.decrypt trigger_reset_main |
Set by vold to shutdown the UI asking for the disk password. |
vold.decrypt trigger_post_fs_data |
Set by vold to prep /data with necessary directories, et al. |
vold.decrypt trigger_restart_framework |
Set by vold to start the real framework and all services. |
vold.decrypt trigger_shutdown_framework |
Set by vold to shutdown the full framework to start encryption. |
vold.decrypt trigger_restart_min_framework |
Set by vold to start the progress bar UI for encryption or prompt for password, depending on the value of ro.crypto.state . |
vold.encrypt_progress |
When the framework starts up, if this property is set, enter the progress bar UI mode. |
vold.encrypt_progress 0 to 100 |
The progress bar UI should display the percentage value set. |
vold.encrypt_progress error_partially_encrypted |
The progress bar UI should display a message that the encryption failed, and give the user an option to factory reset the device. |
vold.encrypt_progress error_reboot_failed |
The progress bar UI should display a message saying encryption completed, and give the user a button to reboot the device. This error is not expected to happen. |
vold.encrypt_progress error_not_encrypted |
The progress bar UI should display a message saying an error occurred, no data was encrypted or lost, and give the user a button to reboot the system. |
vold.encrypt_progress error_shutting_down |
The progress bar UI is not running, so it is unclear who will respond to this error. And it should never happen anyway. |
vold.post_fs_data_done 0 |
Set by vold just before setting vold.decrypt to trigger_post_fs_data . |
vold.post_fs_data_done 1 |
Set by init.rc orinit.rc just after finishing the task post-fs-data . |
init properties
Property | Description |
---|---|
ro.crypto.fs_crypto_blkdev |
Set by the vold command checkpw for later useby the vold command restart . |
ro.crypto.state unencrypted |
Set by init to say this system is running with an unencrypted/data ro.crypto.state encrypted . Set by init to saythis system is running with an encrypted /data . |
ro.crypto.fs_type |
These five properties are set byinit when it tries to mount /data with parameters passed in frominit.rc . vold uses these to setup the crypto mapping. |
ro.crypto.tmpfs_options |
Set by init.rc with the options init should use whenmounting the tmpfs /data filesystem. |
Init actions
on post-fs-data on nonencrypted on property:vold.decrypt=trigger_reset_main on property:vold.decrypt=trigger_post_fs_data on property:vold.decrypt=trigger_restart_min_framework on property:vold.decrypt=trigger_restart_framework on property:vold.decrypt=trigger_shutdown_framework on property:vold.decrypt=trigger_encryption on property:vold.decrypt=trigger_default_encryption