Android加密之全盘加密详解

前言

Android 的安全性问题一直备受关注,Google 在 Android 系统的安全方面也是一直没有停止过更新,努力做到更加安全的手机移动操作系统。

在 Android 的安全性方面,有很多模块:

1 内核安全性
2 应用安全性
3 应用签名
4 身份验证
5 Trusty TEE
6 SELinux
7 加密
等等

其中,加密又分全盘加密(Android 4.4 引入)和文件级加密(Android 7.0 引入),本文将论述加密中的全盘加密的基本知识。全盘加密在 Android 4.4 中引入,在 Android 5.0 中做了比较大的更新。

本文部分片段摘自 Android 官网,融合笔者的个人理解和知识。

什么是全盘加密

全盘加密是使用已加密的密钥对 Android 设备上的所有用户数据进行编码的过程。设备经过加密后,所有由用户创建的数据在写入磁盘之前都会自动加密,并且所有读取操作都会在将数据返回给调用进程之前自动解密数据。

Android 5.0 中又引入了以下新功能:

创建了快速加密方式,这种加密方式只会对数据分区中已使用的分块进行加密,以免首次启动用时过长。目前只有 EXT4 和 F2FS 文件系统支持快速加密。

添加了 forceencrypt fstab 标记,以便在首次启动时进行加密。

添加了对解锁图案和无密码加密的支持。

添加了由硬件支持的加密密钥存储空间,该空间使用可信执行环境(TEE,例如 TrustZone)的签名功能。

全盘加密运作方式

Android 全盘加密基于在块设备层运行的内核功能 dm-crypt。因此,这种加密方式适用于以块设备的形式呈现给内核的嵌入式多媒体卡 (eMMC) 和类似闪存设备。YAFFS 会直接与原始 NAND 闪存芯片交互,无法进行全盘加密。

全盘加密采用的是 128 位高级加密标准 (AES) 算法(搭配密码块链接 (CBC) 和 ESSIV:SHA256)。对主密钥进行加密时使用的是 128 位 AES 算法,并会调用 OpenSSL 库。对于该密钥,您必须使用 128 位或更多位(可以选择 256 位)。

Android 5.0 版中有以下 4 种加密状态:

默认
PIN 码
密码
解锁图案

首次启动时,设备会创建一个随机生成的 128 位主密钥,然后会使用默认密码和存储的盐对其进行哈希处理。默认密码是“default_password”。不过,设备还会通过 TEE(例如 TrustZone)为生成的哈希签名。TEE 会使用相应签名的哈希来加密主密钥。

您可以在 Android 开放源代码项目 cryptfs.c 文件中找到定义的默认密码。

当用户在设备上设置 PIN 码/通行码或密码时,只有 128 位的密钥会被重新加密并存储起来(也就是说,更改用户 PIN 码/通行码/解锁图案不会导致重新加密用户数据)。请注意,受管理的设备可能受 PIN 码、解锁图案或密码限制。

加密操作由 init 和 vold 管理。 init 负责调用 vold,然后 vold 会设置相关属性以触发 init 中的事件。系统的其他部分也会查看这些属性以执行各项任务,例如报告状态、提示输入密码,或有严重错误发生时提示恢复出厂设置。为了调用 vold 中的加密功能,系统会使用命令行工具 vdc 的 cryptfs 命令:checkpw、restart、enablecrypto、changepw、cryptocomplete、verifypw、setfield、getfield、mountdefaultencrypted、getpwtype、getpw 以及 clearpw。

要加密、解密或清空 /data,/data 不得处于装载状态。但要显示任何界面,框架都必须启动,而框架需要 /data 才能运行。为了解决这一冲突,/data 上会装载一个临时文件系统。通过该文件系统,Android 可以提示输入密码、显示进度或根据需要建议清除数据。不过,该文件系统会带来以下限制:要从临时文件系统切换到实际的 /data 文件系统,系统必须停止临时文件系统中打开了文件的所有进程,并在实际的 /data 文件系统中重启这些进程。为此,所有服务都必须位于以下其中一个组内:core、main 和 late_start。

core:启动后一直不会关闭。

main:关闭,然后在用户输入磁盘密码后会重启。

late_start:在 /data 未解密并装载之前,一直不会启动。

为了触发这些操作,vold.decrypt 属性会被设为多种字符串。要结束和重启服务,请使用以下 init 命令:

class_reset:停止相应服务,但允许通过 class_start 重启该服务。

class_start:重启相应服务。

class_stop:停止相应服务并添加 SVC_DISABLED 标记。被停止的服务不会对。

class_start 做出响应。

加密流程和启动流程

使用 forceencrypt 加密新设备

这是 Android 5.0 设备首次启动时的常规流程。

检测带有 forceencrypt 标记的未加密文件系统

/data 未加密,但需要加密,因为 forceencrypt 强制要求进行此项加密。卸载 /data。

开始加密 /data

vold.decrypt = “trigger_encryption” 会触发 init.rc,从而使 vold 对 /data 进行无密码加密。(因为这应该是新设备,还没有设置密码。)

装载 tmpfs

vold 会装载一个 tmpfs /data(使用 ro.crypto.tmpfs_options 中的 tmpfs 选项),并会将 vold.encrypt_progress 属性设为 0。 vold 会准备 tmpfs /data 以便启动已加密的系统,并会将 vold.decrypt 属性设为 trigger_restart_min_framework

启动框架以显示进度

由于设备上几乎没有要加密的数据,加密过程很快就会完成,因此实际上通常并不会显示进度条。如需关于进度界面的更多详细信息,请参阅加密现有设备。

/data 加密后,关闭框架

vold 会将 vold.decrypt 设为 trigger_default_encryption,这会启动 defaultcrypto 服务。(这会启动以下流程来装载默认的已加密用户数据。)trigger_default_encryption 会检查加密类型,以了解 /data 加密是否使用了密码。由于 Android 5.0 设备是在首次启动时加密,应该没有设置任何密码,因此我们要解密并装载 /data。

装载 /data

接下来,init 会使用从 ro.crypto.tmpfs_options(在 init.rc 中设置)中选取的参数在 tmpfs RAMDisk 中装载 /data。

启动框架

将 vold 设为 trigger_restart_framework,这会继续常规启动过程。

启动未进行默认加密的已加密设备

当您启动设有密码的已加密设备时,则会发生该流程。设备的密码可以是 PIN 码、解锁图案或密码。

检测设有密码的已加密设备

会发现 Android 设备已加密,因为设置了 ro.crypto.state = “encrypted” 标记

由于 /data 是使用密码加密的,因此 vold 会将 vold.decrypt 设为 trigger_restart_min_framework。

装载 tmpfs

init 会设置 5 个属性,以保存为 /data(包含从 init.rc 传入的参数)提供的初始装载选项。 vold 会使用这些属性来设置加密映射:

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags (ASCII 码 8 位十六进制数字,以 0x 开头)

启动框架以提示输入密码

框架会启动并看到 vold.decrypt 已设为 trigger_restart_min_framework。这让框架知道自己是在 tmpfs /data 磁盘中启动的,并且需要获取用户密码。

不过,它首先需要确认磁盘是否已经过适当加密。它会向 vold 发送 cryptfs cryptocomplete 命令。 如果加密已成功完成,vold 会返回 0;如果发生内部错误,则会返回 -1;如果加密未成功完成,则会返回 -2。vold 通过查看 CRYPTO_ENCRYPTION_IN_PROGRESS 标记的加密元数据来确定应返回的值。如果设置了此标记,则表示加密过程中断了,并且设备上没有可用的数据。如果 vold 返回错误,界面中应显示一条消息,提示用户重新启动设备并将其恢复出厂设置,并且界面中应为用户提供一个用于执行该操作的按钮。

通过密码解密数据

cryptfs cryptocomplete 成功后,框架会显示一个界面,提示用户输入磁盘密码。界面会向 vold 发送 cryptfs checkpw 命令来检查用户输入的密码。如果密码正确(通过以下方式判定:在临时位置成功装载已解密的 /data,然后将其卸载),vold 会将已解密块设备的名称保存在 ro.crypto.fs_crypto_blkdev 属性中,并向界面返回状态 0。如果密码不正确,则向界面返回 -1。

停止框架

界面会显示加密启动图形,然后使用 cryptfs restart 命令调用 vold。vold 会将 vold.decrypt 属性设为 trigger_reset_main,这会使 init.rc 执行 class_reset main 命令。此命令会停止 main 类中的所有服务,以便卸载 tmpfs /data。

装载 /data

然后,vold 会装载已解密的实际 /data 分区,并准备新的分区(如果加密时采用了首次发布不支持的数据清除选项,则可能永远无法准备就绪)。它会将 vold.post_fs_data_done 属性设为 0,接着将 vold.decrypt 设为 trigger_post_fs_data。这会使 init.rc 运行其 post-fs-data 命令。这些命令会创建所有必要的目录或链接,然后将 vold.post_fs_data_done 设为 1。当 vold 看到该属性中的 1 时,会将 vold.decrypt 属性设为 trigger_restart_framework。这会使 init.rc 再次启动 main 类中的服务,并启动 late_start 类中的服务(这是设备启动后首次启动这些服务)。

启动整个框架

现在,框架会使用已解密的 /data 文件系统启动其所有服务,接下来系统就可以使用了。

代码解读

结合上章节的流程,下面用代码来解析启动未进行默认加密的已加密设备这个流程。

# Android fstab file.
#<src>           <mnt_point> <type>
......
/dev/block/platform/soc.0/f9824900.sdhci/by-name/userdata  /data   ext4 noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc,errors=panic wait,check,fileencryption
......
defaults

这个配置定义在 device/lge/bullhead/fstab_fbe.bullhead 文件中。

如上面的代码,在 /data 的末尾加上 fileencryption,便会进行全盘加密。

步骤1:检测设有密码的已加密设备

//设置ro.crypto.state标记,手机已被用户加密
static int do_mount_all(const std::vector<std::string>& args) {
 ......
 if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
  ActionManager::GetInstance().QueueEventTrigger("encrypt");
 } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
  // 全盘加密,ro.crypto.state = encrypted, ro.crypto.type = block
  property_set("ro.crypto.state", "encrypted");
  property_set("ro.crypto.type", "block");
  //发送vdc 命令 defaultcrypto
  ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
 ......
 } else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
  if (e4crypt_install_keyring()) {
   return -1;
  }
  property_set("ro.crypto.state", "encrypted");
  property_set("ro.crypto.type", "file");
  ......

 return ret;
}

这个方法定义在文件 system/core/init/builtins.cpp 中。

# One shot invocation to deal with encrypted volume.
# do_mount_all 中写入命令 defaultcrypto,执行 vdc 发送命令 mountdefaultencrypted
on defaultcrypto
 exec - root -- /system/bin/vdc --wait cryptfs mountdefaultencrypted
 # vold will set vold.decrypt to trigger_restart_framework (default
 # encryption) or trigger_restart_min_framework (other encryption)

# One shot invocation to encrypt unencrypted volumes
on encrypt
 start surfaceflinger
 exec - root -- /system/bin/vdc --wait cryptfs enablecrypto inplace default noui
 # vold will set vold.decrypt to trigger_restart_framework (default
 # encryption)

这个服务定义在文件 system/vold/vdc.rc 中。

int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
             int argc, char **argv) {
 ......
 } else if (subcommand == "mountdefaultencrypted") {
  ......
  //执行cryptfs_mount_default_encrypted
  std::thread(&cryptfs_mount_default_encrypted).detach();
 }
 ......
}

这个方法定义在文件 vold/CryptCommandListener.cpp 中。

int cryptfs_mount_default_encrypted(void)
{
 int crypt_type = cryptfs_get_password_type();
 ......
 } else if (crypt_type != CRYPT_TYPE_DEFAULT) {
  SLOGD("Password is not default - "
    "starting min framework to prompt");
  //不是默认加密, 设置 vold.decrypt = trigger_restart_min_framework
  property_set("vold.decrypt", "trigger_restart_min_framework");
  return 0;
 } else if (cryptfs_check_passwd(DEFAULT_PASSWORD) == 0) {
 ......

这个方法定义在文件 system/vold/cryptfs.c 中。

#属性vold.decrypt==trigger_restart_min_framework 时执行
on property:vold.decrypt=trigger_restart_min_framework
 # A/B update verifier that marks a successful boot.
 exec - root -- /system/bin/update_verifier trigger_restart_min_framework
 class_start main

这个服务定义在服务 system/core/rootdir/init.rc 中。

class_start main 可知重启 main 类别的服务。main 类别的服务包括:

会重启 zygote。

步骤2:装载 tmpfs

Zygote 启动后,会 fork() system_process 进程,就是运行 SystemServer 代码了。但是 system_process 的运行需要正常的用户空间(/data),所以,需要临时挂载 tmpfs 分区,这个分区是在内存里分配的临时空间。

int CommandListener::StorageCmd::runCommand(SocketClient *cli,
              int argc, char **argv) {
 ......
 if (!strcmp(argv[1], "mountall")) {
  if (argc != 2) {
   cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
   return 0;
  }
  // 挂载所有设备
  fs_mgr_mount_all(fstab);
  cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
  return 0;
 }

这个方法定义在文件 system/vold/CommandListener.cpp 中。

int fs_mgr_mount_all(struct fstab *fstab)
{
 ......
 /* mount(2) returned an error, handle the encryptable/formattable case */
 bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
 //挂载 tmpfs 临时分区
 if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
  ++error_count;
  continue;
 }
 //全盘加密
 encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
 ......
}

这个方法定义在文件 system/core/fs_mgr/fs_mgr.c 中。

步骤3:启动框架以提示输入密码

private void startBootstrapServices() {
 // Only run "core" apps if we're encrypting the device.
 //启动min-framework 显示密码输入界面,仅启动 coreApp, 在AndroidManifest.xml中声明。
 //此时启动的 APP 在 tmpfs 临时分区,所以,所有app都是原始安装状态,不包含任何用户使用产生的数据。
 String cryptState = SystemProperties.get("vold.decrypt");
 if (ENCRYPTING_STATE.equals(cryptState)) {
  Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
  mOnlyCore = true;
 } else if (ENCRYPTED_STATE.equals(cryptState)) {
  Slog.w(TAG, "Device encrypted - only parsing core apps");
  mOnlyCore = true;
 }
 ......
 mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
 mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
 ......

}

这个方法定义在文件frameworks/base/services/java/com/android/server/SystemServer.java 中。

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
   long currentTime, UserHandle user) throws PackageManagerException {
  if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
  PackageParser pp = new PackageParser();
  pp.setSeparateProcesses(mSeparateProcesses);
  // 设置仅解析 core app only,
  pp.setOnlyCoreApps(mOnlyCore);
  .....
}

这个方法定义在文件 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 中

private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
  final PackageLite lite = parseClusterPackageLite(packageDir, 0);

  // 如果不是 !lite.coreApp, 跳过该 app,即启动时,不会安装该app
  if (mOnlyCoreApps && !lite.coreApp) {
   throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
     "Not a coreApp: " + packageDir);
  }

这个方法定义在文件 frameworks/base/core/java/android/content/pm/PackageParser.java 中。

安卓中定义为 coreApp 的应用有:

Framework-res.apk 的 manifest 配置文件如下:

步骤4:通过密码解密数据

这个过程不再阐述。

步骤5:停止框架

#重启 main 类别服务
on property:vold.decrypt=trigger_reset_main
 class_reset main

这个 setion 定义在文件 system/core/rootdir/init.rc 中。

步骤6:装载 /data

static int do_mount_all(const std::vector<std::string>& args) {
 pid_t pid;
 .....
 //
 if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
  // 发送 encrypt 事件到 vdc
  ActionManager::GetInstance().QueueEventTrigger("encrypt");
 } else if
 .....
}

这个方法定义在文件 system/core/init/builtins.cpp 中。

on encrypt
 start surfaceflinger
 exec - root -- /system/bin/vdc --wait cryptfs enablecrypto inplace default noui
 # vold will set vold.decrypt to trigger_restart_framework (default
 # encryption)

这个 setion 定义在文件 system/vold/vdc.rc 中。

on encrypt
 start surfaceflinger
 #发送命令 enablecrypto 到 vold
 exec - root -- /system/bin/vdc --wait cryptfs enablecrypto inplace default noui
 # vold will set vold.decrypt to trigger_restart_framework (default
 # encryption)

这个 setion 定义在文件 system/vold/vdc.rc 中。

int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
             int argc, char **argv) {
 } else if (subcommand == "cryptocomplete") {
  if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
  dumpArgs(argc, argv, -1);
  rc = cryptfs_crypto_complete();
 // 命令是 enablecrypto
 } else if (subcommand == "enablecrypto") {
  .....

  // Spawn as thread so init can issue commands back to vold without
  // causing deadlock, usually as a result of prep_data_fs.
  char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
  char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
  // 执行 do_enablecrypto 方法
  std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
}

这个方法定义在文件 system/vold/CryptCommandListener.cpp 中。

static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
 int rc;
 int tries;
 for (tries = 0; tries < 2; ++tries) {
  // 不是默认加密,运行方法 cryptfs_enable()
  if (type == CRYPT_TYPE_DEFAULT) {
   rc = cryptfs_enable_default(arg2, no_ui);
  } else {
   rc = cryptfs_enable(arg2, type, arg4, no_ui);
  }
  .....
 return -1;
}

这个方法定义在文件 system/vold/CryptCommandListener.cpp 中。

int cryptfs_enable(char *howarg, int type, char *passwd, int no_ui)
{
 return cryptfs_enable_internal(howarg, type, passwd, no_ui);
}

这个方法定义在文件 system/vold/cryptfs.c 中。

int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
       int no_ui)
{
 /* restart the framework. */
 /* Create necessary paths on /data */
 if (prep_data_fs()) {
  goto error_shutting_down;
 }
}

这个方法定义在文件 system/vold/cryptfs.c 中。

static int prep_data_fs(void)
{
 property_set("vold.post_fs_data_done", "0");
 // 设置 vold.decrypt = trigger_post_fs_data,触发 init.rc
 property_set("vold.decrypt", "trigger_post_fs_data");
 SLOGD("Just triggered post_fs_data\n");

 /* Wait a max of 50 seconds, hopefully it takes much less */
 for (i=0; i<DATA_PREP_TIMEOUT; i++) {
  char p[PROPERTY_VALUE_MAX];
  // 等待 init 设置 vold.post_fs_data_done = 1
  property_get("vold.post_fs_data_done", p, "0");
  if (*p == '1') {
   break;
  } else {
   usleep(50000);
  }
 }
}

这个方法定义在文件 system/vold/cryptfs.c 中。

on property:vold.decrypt=trigger_post_fs_data
trigger post-fs-data

这个 setion 定义在文件 system/core/rootdir/init.rc 中。

#创建/data 子目录和链接,启动服务
on post-fs-data
 # We chown/chmod /data again so because mount is run as root + defaults
 chown system system /data
 chmod 0771 /data
 # We restorecon /data in case the userdata partition has been reset.
 restorecon /data

 # start debuggerd to make debugging early-boot crashes easier.
 start debuggerd
 start debuggerd64

 #task4597305 added by xiwu.peng to output logcat to uart
 start logcat2uart

 # Make sure we have the device encryption key.
 start vold
 installkey /data

 # Start bootcharting as soon as possible after the data partition is
 # mounted to collect more data.
 mkdir /data/bootchart 0755 shell shell
 bootchart_init

 .....

 mkdir /data/system_de 0770 system system
 mkdir /data/system_ce 0770 system system

 mkdir /data/misc_de 01771 system misc
 mkdir /data/misc_ce 01771 system misc

 mkdir /data/user 0711 system system
 mkdir /data/user_de 0711 system system
 symlink /data/data /data/user/0

 mkdir /data/media 0770 media_rw media_rw
 mkdir /data/media/obb 0770 media_rw media_rw

 init_user0
 # If there is no fs-post-data action in the init.<device>.rc file, you
 # must uncomment this line, otherwise encrypted filesystems
 # won't work.
 # Set indication (checked by vold) that we have finished this action
 #setprop vold.post_fs_data_done 1

这个 setion 定义在文件 system/core/rootdir/init.rc 中。

static int cryptfs_restart_internal(int restart_main)
{
 // init 做完 post-fs-data,继续往下执行代码
 if (prep_data_fs()) {
   return -1;
 }
 //init 做完 post-fs-data, vold 将 vold.decrypt 设为 trigger_restart_framework, 触发init
 /* startup service classes main and late_start */
 property_set("vold.decrypt", "trigger_restart_framework");
}

这个方法定义在文件 system/vold/cryptfs.c 中。

#重启所有服务
on property:vold.decrypt=trigger_restart_framework
 # A/B update verifier that marks a successful boot.
 exec - root -- /system/bin/update_verifier trigger_restart_framework
 class_start main
 class_start late_start

步骤7:启动整个框架

vold.decrypt = trigger_restart_framework, framework 就可以正常启动了。

加密属性

vold 和 init 之间通过设置属性进行通信。下面列出了可用的加密属性。

vold 属性

属性 说明

vold.decrypt trigger_encryption 以无密码方式加密存储卷。

vold.decrypt trigger_default_encryption 检查存储卷是否采用了无密码加密。如果是,则解密并装载存储卷;如果不是,则将 vold.decrypt 设为 trigger_restart_min_framework。

vold.decrypt trigger_reset_main 由 vold 设置,用于关闭提示输入磁盘密码的界面。

vold.decrypt trigger_post_fs_data 由 vold 设置,用于准备具有必要目录等内容的 /data。

vold.decrypt trigger_restart_framework 由 vold 设置,用于启动实际框架和所有服务。

vold.decrypt trigger_shutdown_framework 由 vold 设置,用于关闭整个框架以开始加密。

vold.decrypt trigger_restart_min_framework 由 vold 设置,用于启动加密进度条界面或提示输入密码,具体取决于 ro.crypto.state 的值。

vold.encrypt_progress 框架启动时,如果设置了此属性,则会进入进度条界面模式。

vold.encrypt_progress 0 to 100 进度条界面中应按照设置显示百分比值。

vold.encrypt_progress error_partially_encrypted 进度条界面中应显示一条消息,告诉用户加密失败,并且界面中应为用户提供一个用于将设备恢复出厂设置的按钮。

vold.encrypt_progress error_reboot_failed 进度条界面中应显示一条消息,告诉用户加密已完成,并且界面中应为用户提供一个用于重新启动设备的按钮。此错误不应发生。

vold.encrypt_progress error_not_encrypted 进度条界面中应显示一条消息,告诉用户发生错误,没有已加密的数据或数据已丢失,并且界面中应为用户提供一个用于重新启动系统的按钮。

vold.encrypt_progress error_shutting_down 进度条界面未运行,因此不清楚谁将响应此错误。在任何情况下,都不应发生此错误。

vold.post_fs_data_done 0 由 vold 在将 vold.decrypt 设为 trigger_post_fs_data 的前一刻设置。

vold.post_fs_data_done 1 由 init.rc 或 init.rc 在完成 post-fs-data 任务之后立即设置。

init 属性

属性 说明

ro.crypto.fs_crypto_blkdev 由 vold 命令 checkpw 设置,供 vold 命令 restart 以后使用。

ro.crypto.state unencrypted 由 init 设置,用于说明相应系统正在未加密的 /data ro.crypto.state encrypted 中运行。由 init 设置,用于说明相应系统正在已加密的 /data 中运行。

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

这 5 个属性由 init 在尝试装载 /data(包含从 init.rc 传入的参数)时设置。vold 会使用这些属性来设置加密映射。

ro.crypto.tmpfs_options 由 init.rc 设置,包含 init 在装载 tmpfs /data 文件系统时应使用的选项。

init 操作

on post-fs-data
on nonencrypted
on property:vold.decrypt=trigger_reset_main
on property:vold.decrypt=trigger_post_fs_data
on property:vold.decrypt=trigger_restart_min_framework
on property:vold.decrypt=trigger_restart_framework
on property:vold.decrypt=trigger_shutdown_framework
on property:vold.decrypt=trigger_encryption
on property:vold.decrypt=trigger_default_encryption.

Android 全盘加密分析到此为止。

以上这篇Android加密之全盘加密详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Android 中 MD5 的几种生成方式(小结)

    Java 提供了 MessageDigest 类用来处理消息摘要算法,如 MD5 , SHA-1 和 SHA-256 等. 1. Java 的标准实现 使用位运算进行进制转换. import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Hash { private static final char[] hexCode = "0123456789ABCDEF&qu

  • Android加密之全盘加密详解

    前言 Android 的安全性问题一直备受关注,Google 在 Android 系统的安全方面也是一直没有停止过更新,努力做到更加安全的手机移动操作系统. 在 Android 的安全性方面,有很多模块: 1 内核安全性 2 应用安全性 3 应用签名 4 身份验证 5 Trusty TEE 6 SELinux 7 加密 等等 其中,加密又分全盘加密(Android 4.4 引入)和文件级加密(Android 7.0 引入),本文将论述加密中的全盘加密的基本知识.全盘加密在 Android 4.4

  • php 生成加密公钥加密私钥实例详解

    php 生成加密公钥加密私钥实例详解 生成公钥私钥     win下必须要openssl.cof支持   liunx一般已自带安装  $config = array( //"digest_alg" => "sha512", "private_key_bits" => 512, //字节数 512 1024 2048 4096 等 "private_key_type" => OPENSSL_KEYTYPE_RS

  • MySQL加密和解密实例详解

    MySQL加密和解密实例详解 数据加密.解密在安全领域非常重要.对程序员而言,在数据库中以密文方式存储用户密码对入侵者剽窃用户隐私意义重大. 有多种前端加密算法可用于数据加密.解密,下面我向您推荐一种简单的数据库级别的数据加密.解密解决方案.以MySQL数据库为例,它内建了相应的加密函数(AES_ENCRYPT() )和解密函数(AES_DECRYPT()). 在建表的时候,要注意字段的类型.如下图所示: 在表中插入加密数据 上面的插入语句有三个字段,"用户名"."密码&qu

  • Java异或技操作给任意的文件加密原理及使用详解

    异或简单介绍:异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1. 简单理解就是不进位加法,如1+1=0,,0+0=0,1+0=1. 需求描述 在信息化时代对数据进行加密是一个很重要的主题,在做项目的过程中,我也实现了一个比较复杂的加密算法,但是由于涉及到的技术是保密的,所以在这里我实现一个比较简单的版本,利用文件的输入输出流和异或操作进行任意文件的加密,关于解密算法,很简单,自己思考下就能解决. 数学原理 该加密算法利用的是

  • vue项目中 使用 pako.js 解密 gzip加密字符串的代码详解

    前言 今天跟后台对接一个接口,接受到一个加密的值,说是通过gzip加密过的,然后就蒙蔽了, 赶紧上百度找了一下资料,通过一篇文章(原文在底部)发现有个js库可以解密,就下载轻松解密了 实现代码 poko.js可至Github下载 https://github.com/nodeca/pako or npm install pako import pako from 'pako' // 一个是加密:window.btoa(),一个是解密:window.atob() function decode(e

  • C# 数据库链接字符串加密解密工具代码详解

    有些项目尤其是WinForm或者是WPF项目,针对一些工具形式的小项目,不想软件流出去之后,懂程序的的拿到手之后一看配置文件就知道了我们数据库的用户名和密码,如果外网能访问的话,那就麻烦大了.所以这里为了防止项目外泄之后这些信息不被别人看到,我们就需要对链接字符串或者其他重要信息进行加密,用的时候在解密. 思路:使用两个数对连接字符串进行加密,再用这两个数进行解密. <add key="ConfigString" value="4HsXBRNXTkeN0ZoKdEwFE

  • Java对称加密工作模式原理详解

    这篇文章主要介绍了Java对称加密工作模式原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 对称加密又分为分组加密和序列密码. 分组密码,也叫块加密(block cyphers),一次加密明文中的一个块.是将明文按一定的位长分组,明文组经过加密运算得到密文组,密文组经过解密运算(加密运算的逆运算),还原成明文组. 序列密码,也叫流加密(stream cyphers),一次加密明文中的一个位.是指利用少量的密钥(制乱元素)通过某种复杂的运算

  • Python使用Crypto库实现加密解密的示例详解

    目录 一:crypto库安装 二:python使用crypto 1:crypto的加密解密组件des.py 2:crypto组件使用 知识补充 一:crypto库安装 pycrypto,pycryptodome是crypto第三方库,pycrypto已经停止更新三年了,所以不建议安装这个库:pycryptodome是pycrypto的延伸版本,用法和pycrypto 是一模一样的:所以只需要安装pycryptodome就可以了 pip install pycryptodome 二:python使

  • Android 帧动画的实例详解

    Android 帧动画的实例详解 对于 Android 帧动画 大体上可以理解成 一张张图片 按一定顺序切换, 这样当连续几张图是一组动画时,就可以连起来了看成是一个小电影,你懂得 好得,比就装到这里,下面开始进入正题,由于产品需求 需要做一个 声音喇叭动态切换的样式,我特么第一就想到是帧动画切换,然后就百度了一些资料,发现 真的, 现在这个网上太多的资料是 copy粘贴过来的, 一错全错,对于这种情况我只想说,made,一群垃圾, 所以今天我将带你们走进Android 正确帧动画地址. 第一步

  • Android NavigationController 右滑手势详解

    苹果一直都在人机交互中尽力做到极致,在iOS7中,新增加了一个小小的功能,也就是这个api:self.navigationController.interactivePopGestureRecognizer.enabled = YES; 这个api功能就是在NavigationController堆栈内的UIViewController可以支持右滑手势,也就是不用点击右上角的返回按钮,轻轻在屏幕左边一滑,屏幕就会返回,随着ios设备屏幕的增大,这个小功能让手指短,拇指大和手残人士看到了福音. 这

随机推荐