Home | History | Annotate | Download | only in encryption
      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.&lt;device&gt;.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