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