Android加密之全盘加密

2022-08-27 11:29:00 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

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 设备首次启动时的常规流程。

  1. 检测带有 forceencrypt 标记的未加密文件系统 /data 未加密,但需要加密,因为 forceencrypt 强制要求进行此项加密。卸载 /data。
  2. 开始加密 /data vold.decrypt = “trigger_encryption” 会触发 init.rc,从而使 vold 对 /data 进行无密码加密。(因为这应该是新设备,还没有设置密码。)
  3. 装载 tmpfs vold 会装载一个 tmpfs /data(使用 ro.crypto.tmpfs_options 中的 tmpfs 选项),并会将 vold.encrypt_progress 属性设为 0。 vold 会准备 tmpfs /data 以便启动已加密的系统,并会将 vold.decrypt 属性设为 trigger_restart_min_framework
  4. 启动框架以显示进度 由于设备上几乎没有要加密的数据,加密过程很快就会完成,因此实际上通常并不会显示进度条。如需关于进度界面的更多详细信息,请参阅加密现有设备。
  5. /data 加密后,关闭框架 vold 会将 vold.decrypt 设为 trigger_default_encryption,这会启动 defaultcrypto 服务。(这会启动以下流程来装载默认的已加密用户数据。)trigger_default_encryption 会检查加密类型,以了解 /data 加密是否使用了密码。由于 Android 5.0 设备是在首次启动时加密,应该没有设置任何密码,因此我们要解密并装载 /data。
  6. 装载 /data 接下来,init 会使用从 ro.crypto.tmpfs_options(在 init.rc 中设置)中选取的参数在 tmpfs RAMDisk 中装载 /data。
  7. 启动框架 将 vold 设为 trigger_restart_framework,这会继续常规启动过程。

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

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

  1. 检测设有密码的已加密设备 会发现 Android 设备已加密,因为设置了 ro.crypto.state = “encrypted” 标记 由于 /data 是使用密码加密的,因此 vold 会将 vold.decrypt 设为 trigger_restart_min_framework。
  2. 装载 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 开头)
  3. 启动框架以提示输入密码 框架会启动并看到 vold.decrypt 已设为 trigger_restart_min_framework。这让框架知道自己是在 tmpfs /data 磁盘中启动的,并且需要获取用户密码。 不过,它首先需要确认磁盘是否已经过适当加密。它会向 vold 发送 cryptfs cryptocomplete 命令。 如果加密已成功完成,vold 会返回 0;如果发生内部错误,则会返回 -1;如果加密未成功完成,则会返回 -2。vold 通过查看 CRYPTO_ENCRYPTION_IN_PROGRESS 标记的加密元数据来确定应返回的值。如果设置了此标记,则表示加密过程中断了,并且设备上没有可用的数据。如果 vold 返回错误,界面中应显示一条消息,提示用户重新启动设备并将其恢复出厂设置,并且界面中应为用户提供一个用于执行该操作的按钮。
  4. 通过密码解密数据 cryptfs cryptocomplete 成功后,框架会显示一个界面,提示用户输入磁盘密码。界面会向 vold 发送 cryptfs checkpw 命令来检查用户输入的密码。如果密码正确(通过以下方式判定:在临时位置成功装载已解密的 /data,然后将其卸载),vold 会将已解密块设备的名称保存在 ro.crypto.fs_crypto_blkdev 属性中,并向界面返回状态 0。如果密码不正确,则向界面返回 -1。
  5. 停止框架 界面会显示加密启动图形,然后使用 cryptfs restart 命令调用 vold。vold 会将 vold.decrypt 属性设为 trigger_reset_main,这会使 init.rc 执行 class_reset main 命令。此命令会停止 main 类中的所有服务,以便卸载 tmpfs /data。
  6. 装载 /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 类中的服务(这是设备启动后首次启动这些服务)。
  7. 启动整个框架 现在,框架会使用已解密的 /data 文件系统启动其所有服务,接下来系统就可以使用了。

代码解读

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

代码语言:javascript复制
# 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:检测设有密码的已加密设备

代码语言:javascript复制
//设置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 中。

代码语言:javascript复制
# 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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
#属性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 分区,这个分区是在内存里分配的临时空间。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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:启动框架以提示输入密码

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中

代码语言:javascript复制
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:停止框架

代码语言:javascript复制
#重启 main 类别服务
on property:vold.decrypt=trigger_reset_main
    class_reset main

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

步骤6:装载 /data

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
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_datan");

    /* 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 中。

代码语言:javascript复制
on property:vold.decrypt=trigger_post_fs_data
    trigger post-fs-data

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

代码语言:javascript复制
#创建/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 中。

代码语言:javascript复制
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 中。

代码语言:javascript复制
#重启所有服务
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 属性

代码语言:javascript复制
属性  说明
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 属性

代码语言:javascript复制
属性  说明
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 操作

代码语言:javascript复制
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 全盘加密分析到此为止。

参考 https://source.android.com/security/encryption/full-disk

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/145227.html原文链接:https://javaforall.cn

0 人点赞