Andoid 3.0的加密实现

来源:互联网 发布:服装批发软件哪个好 编辑:程序博客网 时间:2024/06/10 03:17

快速概要

    如果你想在你的Android3.0的设备上添加加密功能的话,那么你首先要满足一下几点:

    1./data分区必须是在支持块设备形式的接口的设备。eMMC是首选。因为整个加密的都是基于kernel的工作于快设备之上的dm-crypt层。

    2.system/vold/cryptfs.c中的get_fs_size()函数默认把data分区的文件系统认为是ext4.它只是对该分区最后的用来存放crypto footer的16Kbyte的空间做错误检查,确保data分区的文件系统没有使用到这最后的16Kbyte的空间。因为在开发阶段,该函数在开发阶段还是蛮有用的,因为这时的data分区的大小会经常变动。但到了release阶段后就并不是是必须的了。如果说你没有使用ext4的文件系统的话,你要么就把该函数删掉并把对其的调用去掉,或者你可以修改它以适用于你所使用的文件系统。

    3.对于一个设备来说,大多数用来设置及销毁临时的framework的代码段都是存在于那些不需要被改动的文件中。然而init.*.rc文件就需要做一些改动。所有的services必须属于后面的三种类别中的一种,这三种类别为:core、main和late_state。属于core类的services在临时framework拿到passworrd后是不需要停止和重启的。属于main类别的services会在临时framework重启到真正的framework时重启。而属于late_state类别的services则是在临时framework重启进入真正的framework是才启动。所以我们可以把那些在临时framework启动时不需要启动的services放到late_state类别中。

    与此同时,那些需要在data分区创建的设备相关的一些文件夹目录需要放到post-fs-data这个Action中,该Action后必须跟上"setprop vold post_fs_data_done 1"命令。如果说在你的init.*.rc中没有post-fs-data这个Action的话,那就必须在init.rc中的post-fs-data Action后面跟上"setprop vold post_fs_data_done 1"命令。

Android加密时如何工作的

    Android的磁盘加密是基于dm-cryptd的,他是工作在kernel的block device层的一个功能之一。因此这种加密方式就不适用于直接和nand flash 芯片通信的YAFFS文件系统,但却支持emmc或类似的以块设备方式在kernel呈现的flash。目前在这些块设备上首选的文件系统是ext4,即使这与是否使用加密与否并没有什么关系。

    虽然真正的加密工作是标准的linux 内核的功能,但要在一个Android 设备上使用这一功能却变得有些复杂。因为Android 系统是要尽量的避开GPL的约束。所以使用cryptsetup或libdevmapper命令就变得不可能了。于是乎通过ioctl来调用kernel的功能成为了首选。因为Android Vold已经通过这样的方法使得系统可以把app移动到SD卡,所以我们可以利用这些已经做好的工作来帮助完成整个磁盘的加密。首次release的Android 系统加密使用的是128位的AES对称加密以及ESS:SHA256。密钥master key是使用openssl库的128位的AES加密保护。

    一旦把加密的功能加到vold的话,那么调用加密的功能就会如同调用其他的vold的功能一样简单,只需要把其作为一个模块(即cryptfs)加到vold并留出一些接口命令。如checkpw、restart、enablecrypto、changepw和cryptocomplete等。这些命令我们将会在后边描述。

    另外的一个难题就是怎么在系统启动的时候从用户那儿获取到密码。一开始的想法是构造一个轻量级的UI系统通过init把其从ramdisk启动,然后通过这个轻量级的系统来获取密码以使init能解密并挂载data分区。但UI工程师这将会带来很大的工作量并同时提出另一种想法,即让init在启动的时候让framework先进入一个密码输入的界面来获取用户密码然后在在重启进入真正的framework。最后决定使用这种方法于是也就有了接下来要描述的其他的一些决定。特别的,init是通过设置系统属性来通知framework进入密码输入界面的。与此同时,vold、init和frameork之间的通信也是通过一系列的系统属性。这些都将在后边详细描述。

    最后还有一个问题就是关于杀死和重启一部分的services以使得临时data分区能被umount及解密后的data分区能被mount上。因为要想启动临时framework来获取密码就需要先挂载一个tempfs data 分区,这样framework才能启动。但这是那些打开了tempfs data分区时的文件的services就需要被杀死使得tempfs data能被umount,并且这些services需要在解密的data分区mount上后重新启动。于是乎就有了之前说的把services分为三类,即core 、 main 和late_stae。Core类的services在一开始启动后就不会被停止及重启。main类别的services在获取到用户密码后要被停止使得tmpfs data能被umount并在真正的data分区挂载上后重启。而lata_state类别的services则在真正的data分区挂载后才启动。这一系列的操作都是通过接下来下边要描述的vold.decrypt系统属性来时实现的。与此同时一个新的用来停止services的init 命令需要被引入,那即是"class_reset",使用该命令停止的services能够再次的被"class_start"重启,这与"class_stop"命令是不一样的。使用"class_stop"命令停止后的services是不能再被”class_start“重新启动的,因为"class_stop"在停止services的同时也会把标志SVC_DISABLED设置到services的状态中。而该标志即表示该service不能再通过"class_start"重新启动。

加密的系统的启动过程

    1,当init在挂载data分区失败时,它就会先假设文件系统已经被加密过了,于是会同时设置若干的系统属性:ro.crypto.state=”encrypted“ vold.decrypt=1,然后init会使用init.rc中设置的ro.crypto.tmpfs_option的值来挂载一个基于tmpfs ramdisk 的临时data分区。

    如果说init挂载data分区时成功的或,那么它将会把ro.crypto.state设置为”unencrypted“。

    不管是哪一种情况,init都会把最初挂载data分区的option保存到一下的5个系统属性中:ro.crypto.fs_type ro.crypto.fs_real_blkdev ro.crypto.fs_mnt_point ro.crypto.fs_options ro.crypto.fs_flags(保存为0x开头的Ascii的8个十六进制数)。

    2.但framework启动的时候如果检测到vold.decrypt的值为"1"时就表明此时的framework是在tmpfs 的临时data分区上启动的,并且接下来需要进入密码输入界面来获取密码。当然这是系统会首再次确认磁盘是否真的的被加密,系统通过给vold发送"cryptfs cryptocomplete"来做检查。如果vold返回0的话那么说明data分区被加密了。返回-1表示内部出错或返回-2表示加密没有成功完成。系统是通过检查crypto footer中的CRYPTO_ENCRYPTION_IN_PROGRESS标志来判断是否有加密成功完成,如果说该标志被设置了就表明加密过程被打断了,同时设备上的数据已经不可用了。如果vold返回错误的话,系统会弹出信息框提示用户需要重启设备和对设备进行出产设置,并会给用户一个确定按钮来执行此操作。

    3.在此假设命令"cryptfs cryptocomplete"成功的返回,这时系统就会进入用户密码输入界面来获取用户加密密码。系统会通过发送命令"cryptfs checkpw"给vold来检查用户输入的密码是否真确(vold如果能成功的把解密的data分区临时的挂载并卸载就表明密码正确),如果密码正确的话,vold会把解密的data分区所在的块设备明保存到ro.crypto.fs_crypto_blkdev并同时返回一个0给系统,如果说用户输入的密码是错误的话则直接返回-1给系统。

    4.但用户输入正确的密码后,系统会弹出一个重启的界面并通过"cryptfs restart"通知vold 系统重启。vold此时会设置属性vold.decrypt的值为"trigger_reset_main",这将会触发init.rc去执行"class_reset main".该操作我们上面说过会停止main类别的service使得tmpfs 的data分区能够被umount,紧接着就是把真正的data分区挂载上并对其做一些初始化的准备(当选择了wipe option时data分区就需要做这一工作,但目前并没有支持该option)。系统接下来及时设置vold.post_fs_data_done为"0"和vold.decrypt为"trigger_post_fs_dat",这将会触发init.rc去执行init.rc或init.*.rc中的post-fs-data命令。该命令会在data分区创建一些必要的文件夹,链接等文件,然后系统又把vold.post_fs_data_done谁为"1",而vold一直在等该属性被设置为1,这是Vold就会把属性vold.decrypt设置为"trigger_restart_framework"来触发init.rc去启动main类别的service和late_start类别的service。

    到此framework就真正的启动了需要使用data分区数据的service而真正的进入了系统等待用户使用。

在设备上使用Andorid 加密功能

    对于第一次的release目前只支持in place的加密,加密设备需要framework 关闭掉并umount data分区来对设备进行逐扇区的加密。加密完后系统重启进入上面描述的启动加密的Android系统的部分的流程。下面将对加密的流程作详细的介绍。

    1.当用户通过UI选择了加密设备时,系统此时就会检测设备是否已经充满了电并且插上了AC充电器在充电以保证在整个加密的过程中有足够的电量来完成加密工作。因为在整个加密的过程中一旦设备没有了电那么设备上的 数据就会处于一个部分加密的状态。这时设备就只能做factory reset的操作(此时所有的数据将会丢失)。

    当用户通过一系列的确认后。系统就会使用使用用户的password来调用vold对设备进行加密。

    2.Vold首先会作一些错误检查来确认加密是否可以进行,如果说加密不可以进行将会返回-1并同时在log中打印出原因。如果加密可以进行的话,Vold会设置系统属性vold.decrypt的值为"tirgger_shutdown_framework"。这将会触发init.rc去停止掉late_state类和main类别的service。接下来vold会把/mnt/scard和/data umount掉。

    3.如果是以 inplace的方式来加密,vold会在tmpfs上持载一个临时的data分区(使用ro.crypto.tmpfs_options的值来作挂载参数)并同时设置系统属性vold.encrypt_progress 的值为"0"。然后vold会对tmpfs 的临时data分区的文件系统作一些准备工作就如同上边的加密系统的启动的第3步所描述的一样。紧接着vold会设置vold.decrypt为"trgger_restart_min_framework",这将会触发init.rc去把上边关掉的main类别的service重新的启动。这时framework会启动并检测到vold.encrypt_progress的值是"0"就会显示一个进度条并每5秒读一次该属性的值来更新进度条的值。

    4.Vold接下来会设置crypto映射,这将会创建一个虚拟的crypto 块设备并对应的关联映射到真正的data分区所在的块设备,但整个加密或解密都是按所写入或读出的扇区来进行的,然后就是创建并写入crypto footer。

    crypto footer包含了加密的一些信息及用来解密的密钥(master key),密钥是通过读取/dev/urandom得到的一个128位的数字。并且系统会使用SSL 库的PBKDF2函数对用户的密码hash的结果来对该密钥加密保护。crypto footer也包含了一个随机种子值(从/dev/urandom得到)用来增加PBKDF2的hash值的信息熵,并阻止password会受到rainbow table的攻击破解。与些同时,crypto footer中的CRYPT_ENCRYPTION_IN_PROGRESS也会被设置为对应的值来表明加密是否成功。更多关于crypto footer的信息可以参考cryptfs.h文件。crypto footer将会被存放在/data所在的分区的最后16Kbytes,所以data分区的文件系统是不占用到这个部分的。

    5.如果加密时使用了wipe选项,vold将会使用"make_ext4fs"来对该分区格式化,这将要注意不要把最后的16Kbytes给格进data分区的文件系统。

    如果加密是inplace方式的话,vold将会开始不断的从真正的块设备读取每一扇区的值并将其写入加密的块设备。这个过程在Motorol Xoom的30Gbyte的分区上面使用了1个小时。具体的时间会因不同的硬件有所变化。整个加密的过程中每完成一个perent就会相应的更新vold.encrypt_pogress的值,系统的UI也会每5秒钟读取该属性的值来更新进度条的状态。

    6.不管是哪一种的加密方式,在加密成功后vold会把crypt footer中的ENCRYPTION_IN_PROGRESS的值清掉并重新启动系统。如果在重启系统时有错误发生,vold会设置vold.encrypt_progress的值为"error_reboot_failde"并且UI会让用户选择重启,但这并不是我们预期发生的。

    7.如果在加密的过程中发生了错误,但止时的的数据还没有被开始加密并且此时frameork已经起来(在第3部分我们有重新启动main类别的service),vold会把属性vold.encrypt_progress的值设置为"error_not_encrypted"并且让用户选择重启及告知用户加密有进行。如果说错误发生在framework被关掉后并且在进度条出现之前。vold会直接重启系统,如果此时重启失败,vold会设置vold.encrypt_progress为"error_shutting_down"并返回-1,但这个错误是不可能被捕获到的并且不是我们的预期出现的。

     如果在真正的对块设备加密的时候检测到错误的发生,vold会设置vold.encrypt_progress为"error_partially_encrypted"并返回-1,这里系统将会弹出信息框提示用户加密失败并让用户选择对设备进行factory reset。

 

密码修改

    当要对加密密码做修改时,系统会通过"cryptfs changepw"来通知vold使用新的密码对密钥(master key)重新加密保护。当然用户更改密码就是更换锁屏的pin或密码就可以。


加密相关的系统属性

属性名称              属性值                                 注解
vold.decrypt  1                               Set by init to tell the UI to ask                                              for the disk pwvold.decrypt  trigger_reset_main              Set by vold to shutdown the UI                                              asking for the disk passwordvold.decrypt  trigger_post_fs_data            Set by vold to prep /data with                                              necessary dirs, et al.vold.decrypt  trigger_restart_framework       Set by vold to start the real                                              framework and all servicesvold.decrypt  trigger_shutdown_framework      Set by vold to shutdown the full                                              framework to start encryptionvold.decrypt  trigger_restart_min_framework   Set by vold to start the progress                                              bar UI for encryption.vold.enrypt_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 occured,                                              and 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's 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 or init.<device>.rc                                              just after finishing the task                                              post-fs-data.ro.crypto.fs_crypto_blkdev                    Set by the vold command checkpw                                              for later use by the vold command                                              restart.ro.crypto.state unencrypted                   Set by init to say this system is                                              running with an unencrypted /dataro.crypto.state encrypted                     Set by init to say this system is                                              running with an encrypted /dataro.crypto.fs_type                             These 5 properties are set by initro.crypto.fs_real_blkdev                      when it tries to mount /data withro.crypto.fs_mnt_point                        parameters passed in from init.rc.ro.crypto.fs_options                          vold uses these to setup thero.crypto.fs_flags                            crypto mapping.ro.crypto.tmpfs_options                       Set by init.rc with the options                                              init should use when mounting                                              the tmpfs /data filesystem.

Init.rc中加密相关的Action

on post-fs-dataon nonencryptedon property:vold.decrypt=trigger_reset_mainon property:vold.decrypt=trigger_post_fs_dataon property:vold.decrypt=trigger_restart_min_frameworkon property:vold.decrypt=trigger_restart_frameworkon property:vold.decrypt=trigger_shutdown_framework
原文地址:http://source.android.com/tech/encryption/android_crypto_implementation.html
转载请注明出处:http://blog.csdn.net/godisagirl2/article/details/8989216
南国小书生译

原创粉丝点击