1 <!-- 2 Copyright 2011 The Android Open Source Project 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 --> 16 17 # Notes on the implementation of encryption in Android 3.0 18 <br /> 19 20 ## Quick summary for 3rd parties. 21 22 If you want to enable encryption on your device based on Android 3.0 23 aka Honeycomb, there are only a few requirements: 24 25 1. The /data filesystem must be on a device that presents a block device 26 interface. eMMC is used in the first devices. This is because the 27 encryption is done by the dm-crypt layer in the kernel, which works 28 at the block device layer. 29 30 2. The function get_fs_size() in system/vold/cryptfs.c assumes the filesystem 31 used for /data is ext4. It's just error checking code to make sure the 32 filesystem doesn't extend into the last 16 Kbytes of the partition where 33 the crypto footer is kept. It was useful for development when sizes were 34 changing, but should not be required for release. If you are not using 35 ext4, you can either delete it and the call to it, or fix it to understand 36 the filesystem you are using. 37 38 3. Most of the code to handle the setup and teardown of the temporary framework 39 is in files that are not usually required to be changed on a per device 40 basis. However, the init.<device>.rc file will require some changes. All 41 services must be put in one of three classes: core, main or late_state. 42 Services in the core class are not shutdown and restarted when the 43 temporary framework gets the disk password. Services in the main class 44 are restarted when the framework is restarted. Services in late_start are 45 not started until after the temporary framework is restarted. Put services 46 here that are not required to be running while the temporary framework 47 gets the disk password. 48 49 Also any directories that need to be created on /data that are device 50 specific need to be in the Action for post-fs-data, and that Action must end 51 with the command "setprop vold.post_fs_data_done 1". If your 52 init.<device>.rc file does not have a post-fs-data Action, then the 53 post-fs-data Action in the main init.rc file must end with the command 54 "setprop vold.post_fs_data_done 1". 55 56 57 ## How Android encryption works 58 59 Disk encryption on Android is based on dm-crypt, which is a kernel feature that 60 works at the block device layer. Therefore, it is not usable with YAFFS, which 61 talks directly to a raw nand flash chip, but does work with emmc and similar 62 flash devices which present themselves to the kernel as a block device. The 63 current preferred filesystem to use on these devices is ext4, though that is 64 independent of whether encryption is used or not. 65 66 While the actual encryption work is a standard linux kernel feature, enabling it 67 on an Android device proved somewhat tricky. The Android system tries to avoid 68 incorporating GPL components, so using the cryptsetup command or libdevmapper 69 were not available options. So making the appropriate ioctl(2) calls into the 70 kernel was the best choice. The Android volume daemon (vold) already did this 71 to support moving apps to the SD card, so I chose to leverage that work 72 for whole disk encryption. The actual encryption used for the filesystem for 73 first release is 128 AES with CBC and ESSIV:SHA256. The master key is 74 encrypted with 128 bit AES via calls to the openssl library. 75 76 Once it was decided to put the smarts in vold, it became obvious that invoking 77 the encryption features would be done like invoking other vold commands, by 78 adding a new module to vold (called cryptfs) and teaching it various commands. 79 The commands are checkpw, restart, enablecrypto, changepw and cryptocomplete. 80 They will be described in more detail below. 81 82 The other big issue was how to get the password from the user on boot. The 83 initial plan was to implement a minimal UI that could be invoked from init 84 in the initial ramdisk, and then init would decrypt and mount /data. However, 85 the UI engineer said that was a lot of work, and suggested instead that init 86 communicate upon startup to tell the framework to pop up the password entry 87 screen, get the password, and then shutdown and have the real framework started. 88 It was decided to go this route, and this then led to a host of other decisions 89 described below. In particular, init set a property to tell the framework to go 90 into the special password entry mode, and that set the stage for much 91 communication between vold, init and the framework using properties. The 92 details are described below. 93 94 Finally, there were problems around killing and restarting various services 95 so that /data could be unmounted and remounted. Bringing up the temporary 96 framework to get the user password requires that a tmpfs /data filesystem be 97 mounted, otherwise the framework will not run. But to unmount the tmpfs /data 98 filesystem so the real decrypted /data filesystem could be mounted meant that 99 every process that had open files on the tmpfs /data filesystem had to be killed 100 and restarted on the real /data filesystem. This magic was accomplished by 101 requiring all services to be in 1 of 3 groups: core, main and late_start. 102 Core services are never shut down after starting. main services are shutdown 103 and then restarted after the disk password is entered. late_start services 104 are not started until after /data has been decrypted and mounted. The magic 105 to trigger these actions is by setting the property vold.decrypt to various 106 magic strings, which is described below. Also, a new init command "class_reset" 107 was invented to stop a service, but allow it to be restarted with a 108 "class_start" command. If the command "class_stop" was used instead of the 109 new command "class_reset" the flag SVC_DISABLED was added to the state of 110 any service stopped, which means it would not be started when the command 111 class_start was used on its class. 112 113 ## Booting an encrypted system. 114 115 1. When init fails to mount /data, it assumes the filesystem is encrypted, 116 and sets several properties: 117 ro.crypto.state = "encrypted" 118 vold.decrypt = 1 119 It then mounts a /data on a tmpfs ramdisk, using parameters it picks 120 up from ro.crypto.tmpfs_options, which is set in init.rc. 121 122 If init was able to mount /data, it sets ro.crypto.state to "unencrypted". 123 124 In either case, init then sets 5 properties to save the initial mount 125 options given for /data in these properties: 126 ro.crypto.fs_type 127 ro.crypto.fs_real_blkdev 128 ro.crypto.fs_mnt_point 129 ro.crypto.fs_options 130 ro.crypto.fs_flags (saved as an ascii 8 digit hex number preceded by 0x) 131 132 2. The framework starts up, and sees that vold.decrypt is set to "1". This 133 tells the framework that it is booting on a tmpfs /data disk, and it needs 134 to get the user password. First, however, it needs to make sure that the 135 disk was properly encrypted. It sends the command "cryptfs cryptocomplete" 136 to vold, and vold returns 0 if encryption was completed successfully, or -1 137 on internal error, or -2 if encryption was not completed successfully. 138 Vold determines this by looking in the crypto footer for the 139 CRYPTO_ENCRYPTION_IN_PROGRESS flag. If it's set, the encryption process 140 was interrupted, and there is no usable data on the device. If vold returns 141 an error, the UI should pop up a message saying the user needs to reboot and 142 factory reset the device, and give the user a button to press to do so. 143 144 3. Assuming the "cryptfs cryptocomplete" command returned success, the 145 framework should pop up a UI asking for the disk password. The UI then 146 sends the command "cryptfs checkpw <passwd>" to vold. If the password 147 is correct (which is determined by successfully mounting the decrypted 148 at a temporary location, then unmounting it), vold saves the name of the 149 decrypted block device in the property ro.crypto.fs_crypto_blkdev, and 150 returns status 0 to the UI. If the password is incorrect, it returns -1 151 to the UI. 152 153 4. The UI puts up a crypto boot graphic, and then calls vold with the command 154 "cryptfs restart". vold sets the property vold.decrypt to 155 "trigger_reset_main", which causes init.rc to do "class_reset main". This 156 stops all services in the main class, which allows the tmpfs /data to be 157 unmounted. vold then mounts the decrypted real /data partition, and then 158 preps the new partition (which may never have been prepped if it was 159 encrypted with the wipe option, which is not supported on first release). 160 It sets the property vold.post_fs_data_done to "0", and then sets 161 vold.decrypt to "trigger_post_fs_dat". This causes init.rc to run the 162 post-fs-data commands in init.rc and init.<device>.rc. They will create 163 any necessary directories, links, et al, and then set vold.post_fs_data_done 164 to "1". Vold waits until it sees the "1" in that property. Finally, vold 165 sets the property vold.decrypt to "trigger_restart_framework" which causes 166 init.rc to start services in class main again, and also start services 167 in class late_start for the first time since boot. 168 169 Now the framework boots all its services using the decrypted /data 170 filesystem, and the system is ready for use. 171 172 ## Enabling encryption on the device. 173 174 For first release, we only support encrypt in place, which requires the 175 framework to be shutdown, /data unmounted, and then every sector of the 176 device encrypted, after which the device reboots to go through the process 177 described above. Here are the details: 178 179 1. From the UI, the user selects to encrypt the device. The UI ensures that 180 there is a full charge on the battery, and the AC adapter is plugged in. 181 It does this to make sure there is enough power to finish the encryption 182 process, because if the device runs out of power and shuts down before it 183 has finished encrypting, file data is left in a partially encrypted state, 184 and the device must be factory reset (and all data lost). 185 186 Once the user presses the final button to encrypt the device, the UI calls 187 vold with the command "cryptfs enablecrypto inplace <passwd>" where passwd 188 is the user's lock screen password. 189 190 2. vold does some error checking, and returns -1 if it can't encrypt, and 191 prints a reason in the log. If it thinks it can, it sets the property 192 vold.decrypt to "trigger_shutdown_framework". This causes init.rc to 193 stop services in the classes late_start and main. vold then unmounts 194 /mnt/sdcard and then /data. 195 196 3. If doing an inplace encryption, vold then mounts a tmpfs /data (using the 197 tmpfs options from ro.crypto.tmpfs_options) and sets the property 198 vold.encrypt_progress to "0". It then preps the tmpfs /data filesystem as 199 mentioned in step 3 for booting an encrypted system, and then sets the 200 property vold.decrypt to "trigger_restart_min_framework". This causes 201 init.rc to start the main class of services. When the framework sees that 202 vold.encrypt_progress is set to "0", it will bring up the progress bar UI, 203 which queries that property every 5 seconds and updates a progress bar. 204 205 4. vold then sets up the crypto mapping, which creates a virtual crypto block 206 device that maps onto the real block device, but encrypts each sector as it 207 is written, and decrypts each sector as it is read. vold then creates and 208 writes out the crypto footer. 209 210 The crypto footer contains details on the type of encryption, and an 211 encrypted copy of the master key to decrypt the filesystem. The master key 212 is a 128 bit number created by reading from /dev/urandom. It is encrypted 213 with a hash of the user password created with the PBKDF2 function from the 214 SSL library. The footer also contains a random salt (also read from 215 /dev/urandom) used to add entropy to the hash from PBKDF2, and prevent 216 rainbow table attacks on the password. Also, the flag 217 CRYPT_ENCRYPTION_IN_PROGRESS is set in the crypto footer to detect failure 218 to complete the encryption process. See the file cryptfs.h for details 219 on the crypto footer layout. The crypto footer is kept in the last 16 220 Kbytes of the partition, and the /data filesystem cannot extend into that 221 part of the partition. 222 223 5. If told was to enable encryption with wipe, vold invokes the command 224 "make_ext4fs" on the crypto block device, taking care to not include 225 the last 16 Kbytes of the partition in the filesystem. 226 227 If the command was to enable inplace, vold starts a loop to read each sector 228 of the real block device, and then write it to the crypto block device. 229 This takes about an hour on a 30 Gbyte partition on the Motorola Xoom. 230 This will vary on other hardware. The loop updates the property 231 vold.encrypt_progress every time it encrypts another 1 percent of the 232 partition. The UI checks this property every 5 seconds and updates 233 the progress bar when it changes. 234 235 6. When either encryption method has finished successfully, vold clears the 236 flag ENCRYPTION_IN_PROGRESS in the footer, and reboots the system. 237 If the reboot fails for some reason, vold sets the property 238 vold.encrypt_progress to "error_reboot_failed" and the UI should 239 display a message asking the user to press a button to reboot. 240 This is not expected to ever occur. 241 242 7. If vold detects an error during the encryption process, and if no data has 243 been destroyed yet and the framework is up, vold sets the property 244 vold.encrypt_progress to "error_not_encrypted" and the UI should give the 245 user the option to reboot, telling them that the encryption process 246 never started. If the error occurs after the framework has been torn 247 down, but before the progress bar UI is up, vold will just reboot the 248 system. If the reboot fails, it sets vold.encrypt_progress to 249 "error_shutting_down" and returns -1, but there will not be anyone 250 to catch the error. This is not expected to happen. 251 252 If vold detects an error during the encryption process, it sets 253 vold.encrypt_progress to "error_partially_encrypted" and returns -1. 254 The UI should then display a message saying the encryption failed, and 255 provide a button for the user to factory reset the device. 256 257 ## Changing the password 258 259 To change the password for the disk encryption, the UI sends the command 260 "cryptfs changepw <newpw>" to vold, and vold re-encrypts the disk master 261 key with the new password. 262 263 ## Summary of related properties 264 265 Here is a table summarizing the various properties, their possible values, 266 and what they mean: 267 268 269 vold.decrypt 1 Set by init to tell the UI to ask 270 for the disk pw 271 272 vold.decrypt trigger_reset_main Set by vold to shutdown the UI 273 asking for the disk password 274 275 vold.decrypt trigger_post_fs_data Set by vold to prep /data with 276 necessary dirs, et al. 277 278 vold.decrypt trigger_restart_framework Set by vold to start the real 279 framework and all services 280 281 vold.decrypt trigger_shutdown_framework Set by vold to shutdown the full 282 framework to start encryption 283 284 vold.decrypt trigger_restart_min_framework Set by vold to start the progress 285 bar UI for encryption. 286 287 vold.enrypt_progress When the framework starts up, if 288 this property is set, enter the 289 progress bar UI mode. 290 291 vold.encrypt_progress 0 to 100 The progress bar UI should display 292 the percentage value set. 293 294 vold.encrypt_progress error_partially_encrypted The progress bar UI should 295 display a message that the 296 encryption failed, and give 297 the user an option to factory 298 reset the device. 299 300 vold.encrypt_progress error_reboot_failed The progress bar UI should display 301 a message saying encryption 302 completed, and give the user a 303 button to reboot the device. 304 This error is not expected to 305 happen. 306 307 vold.encrypt_progress error_not_encrypted The progress bar UI should display 308 a message saying an error occured, 309 and no data was encrypted or lost, 310 and give the user a button to 311 reboot the system. 312 313 vold.encrypt_progress error_shutting_down The progress bar UI is not 314 running, so it's unclear who 315 will respond to this error, 316 and it should never happen 317 anyway. 318 319 vold.post_fs_data_done 0 Set by vold just before setting 320 vold.decrypt to 321 trigger_post_fs_data. 322 323 vold.post_fs_data_done 1 Set by init.rc or init.<device>.rc 324 just after finishing the task 325 post-fs-data. 326 327 ro.crypto.fs_crypto_blkdev Set by the vold command checkpw 328 for later use by the vold command 329 restart. 330 331 ro.crypto.state unencrypted Set by init to say this system is 332 running with an unencrypted /data 333 334 ro.crypto.state encrypted Set by init to say this system is 335 running with an encrypted /data 336 337 ro.crypto.fs_type These 5 properties are set by init 338 ro.crypto.fs_real_blkdev when it tries to mount /data with 339 ro.crypto.fs_mnt_point parameters passed in from init.rc. 340 ro.crypto.fs_options vold uses these to setup the 341 ro.crypto.fs_flags crypto mapping. 342 343 ro.crypto.tmpfs_options Set by init.rc with the options 344 init should use when mounting 345 the tmpfs /data filesystem. 346 347 ## Summary of new init actions 348 349 A list of the new Actions that are added to init.rc and/or init.<device>.rc: 350 351 on post-fs-data 352 on nonencrypted 353 on property:vold.decrypt=trigger_reset_main 354 on property:vold.decrypt=trigger_post_fs_data 355 on property:vold.decrypt=trigger_restart_min_framework 356 on property:vold.decrypt=trigger_restart_framework 357 on property:vold.decrypt=trigger_shutdown_framework 358 359 360