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