美文网首页Android
Android加密之文件级加密

Android加密之文件级加密

作者: FamilyYuan | 来源:发表于2017-08-11 14:58 被阅读0次

    Android加密之文件级加密

    前置文章

    《Android加密之全盘加密》

    《Android系统之System Server大纲》

    前言

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

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

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

    其中,加密又分全盘加密(Android 4.4 引入,《Android加密之全盘加密》)和文件级加密(Android 7.0 引入),本文将论述加密中的文件级加密的基本知识。

    什么是文件级加密

    Android 7.0 及更高版本支持文件级加密 (FBE)。采用文件级加密时,可以使用不同的密钥对不同的文件进行加密,并且可以对这些文件进行单独解密。

    全盘加密和文件级加密的区别

    借助文件级加密,Android 7.0 中引入了一项称为直接启动的新功能。该功能处于启用状态时,已加密设备在启动后将直接进入锁定屏幕。之前,在使用全盘加密 (FDE) 的已加密设备上,用户在访问任何数据之前都需要先提供凭据,从而导致手机无法执行除最基本操作之外的所有其他操作。例如,闹钟无法运行,无障碍服务不可用,手机无法接电话,而只能进行基本的紧急拨号操作。

    文件级加密概述

    引入文件级加密 (FBE) 和新 API 后,便可以将应用设为加密感知型应用,这样一来,它们将能够在受限环境中运行。这些应用将可以在用户提供凭据之前运行,同时系统仍能保护私密用户信息。

    在启用了 FBE 的设备上,每位用户均有两个可供应用使用的存储位置:

    • 凭据加密 (CE) 存储空间:这是默认存储位置,只有在用户解锁设备后才可用。
    • 设备加密 (DE) 存储空间:在直接启动模式期间以及用户解锁设备后均可用。

    这种区分能够使工作资料更加安全,因为这样一来,加密不再只基于启动时密码,从而能够同时保护多位用户。

    Direct Boot API 允许加密感知型应用访问上述每个区域。应用生命周期会发生一些变化,以便在用户的 CE 存储空间因用户在锁定屏幕上首次输入凭据而解锁时,或者在工作资料提供工作挑战时,通知应用。无论是否实现了 FBE,运行 Android 7.0 的设备都必须要支持这些新的 API 和生命周期。不过,如果没有 FBE,DE 和 CE 存储空间将始终处于解锁状态。

    启用文件级加密

    通过将不带参数的 fileencryption 标记添加到 userdata 分区最后一列的 fstab 行中,可以启用 FBE。

    直接启动感知型应用

    为了实现系统应用的快速迁移,新增了两个可在应用级别设置的属性。defaultToDeviceProtectedStorage 属性仅适用于系统应用,directBootAware 属性则适用于所有应用。

    <application
    android:directBootAware="true"
    android:defaultToDeviceProtectedStorage="true">

    应用级别的 directBootAware 属性的含义是将相应应用中的所有组件均标记为加密感知型组件。

    defaultToDeviceProtectedStorage 属性用于将默认的应用存储位置重定向到 DE 存储空间(而非 CE 存储空间)。使用此标记的系统应用必须要仔细审核存储在默认位置的所有数据,并将敏感数据的路径更改为使用 CE 存储空间。使用此选项的设备制造商应仔细检查要存储的数据,以确保其中不含任何个人信息。

    在这种模式下运行时,以下系统 API 可在需要时用于明确管理由 CE 存储空间支持的 Context(这些 API 与设备保护存储空间适用的同类 API 相对应)。

    • StorageManager.isFileEncryptedNativeOrEmulated()
    • Context.createCredentialProtectedStorageContext()
    • Context.isCredentialProtectedStorage()

    DE 存储空间支持的 Context

    • Context.createDeviceProtectedStorageContext()
    • Context.isDeviceProtectedStorage()

    启用文件级加密的条件

    • 对 EXT4 加密的内核支持(内核配置选项:EXT4_FS_ENCRYPTION)
    • 基于 1.0 或 2.0 版 HAL 的 Keymaster 支持。不支持 Keymaster 0.3,因为它既不提供必要的功能,也不能保证为加密密钥提供充分保护。
    • 必须在可信执行环境 (TEE) 中实现 Keymaster/Keystore 和 Gatekeeper,以便为 DE 密钥提供保护,从而使未经授权的操作系统(刷到设备上的定制操作系统)无法直接请求 DE 密钥。
    • 内核加密性能必须要在使用 AES XTS 时至少达到 50MB/s,以确保良好的用户体验。
    • 硬件信任根和验证启动需要绑定到 Keymaster 初始化进程,以确保未经授权的操作系统无法获取设备加密凭据。

    加密过程

    密钥创建

    首次创建设备的 userdata 分区时,会由 init 脚本应用基本结构和政策。这些脚本将触发创建首位用户(用户 0)的 CE 密钥和 DE 密钥,并定义要使用这些密钥加密哪些目录。创建其他用户和资料时,会生成必要的其他密钥并将其存储在密钥代码库中;接下来会创建它们的凭据和设备存储位 置,并且加密政策会将这些密钥关联到相应目录。

    DE密钥

    触发 late-init action

    // 开机执行init.cpp,
    int main(int argc, char** argv) {
        ......
        // 解析 init.rc file
        Parser& parser = Parser::GetInstance();
        parser.ParseConfig("/init.rc");
        
        // Don't mount filesystems or start core system services in charger mode.
        std::string bootmode = property_get("ro.bootmode");
        if (bootmode == "charger") {
            am.QueueEventTrigger("charger");
        } else {
            // 触发 late-init action
            am.QueueEventTrigger("late-init");
        }
        ......
    }
    

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

    触发 post-fs-data

    on late-init
        .....
        trigger post-fs
        # Now we can mount /data. File encryption requires keymaster to decrypt
        # /data, which in turn can only be loaded when system properties are present
        trigger post-fs-data
        .....
    

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

    执行 installkey 命令

    on post-fs-data
        chown system system /data
        chmod 0771 /data
        # Make sure we have the device encryption key.
        start vold
        #执行 installkey 命令
        installkey /data
    

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

    命令 installkey 实质执行 do_installkey 函数

    BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        static const Map builtin_functions = {
            .....
            {"installkey",              {1,     1,    do_installkey}},
            {"load_persist_props",      {0,     0,    do_load_persist_props}},
            .....
        };
        return builtin_functions;
    

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

    do_installkey() 函数定义如下

    // 是否是 文件级加密
    static bool is_file_crypto() {
        // 文件级加密 ro.crypto.type 的值是 file, 全盘加密是 block
        std::string value = property_get("ro.crypto.type");
        return value == "file";
    }
    
    static int do_installkey(const std::vector<std::string>& args) {
        // 检查是否是文件级加密
        if (!is_file_crypto()) {
            return 0;
        }
        // 创建密钥
        return e4crypt_create_device_key(args[1].c_str(),
                                         do_installkeys_ensure_dir_exists);
    }
    

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

    ro.crypto.type 在函数 do_mount_all() 中设置

    static int do_mount_all(const std::vector<std::string>& args) {
        } 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");
    }
    

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

    回到 do_installkey() 函数,e4crypt_create_device_key() 定义如下

    int e4crypt_create_device_key(const char* dir,
                                  int ensure_dir_exists(const char*))
    {
        init_logging();
        .....
        // 执行 vdc, 传入命令 enablefilecrypto, 同时需要注意参数 cryptfs
        const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto" };
        // 从 init, 到 vdc, 注意参数 argv[]
        int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
        LOG(INFO) << "enablefilecrypto result: " << rc;
        return rc;
    }
    

    这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。

    android_fork_execvp() 实质是调用函数 android_fork_execvp_ext()

    static inline int android_fork_execvp(int argc, char* argv[], int *status,
                                         bool ignore_int_quit, bool logwrap)
    {
        // 实质是调用函数这个函数
        return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
                                       (logwrap ? LOG_ALOG : LOG_NONE), false, NULL,
                                       NULL, 0);
    }
    

    这个方法定义在文件 system/core/logwrapper/include/logwrap/logwrap.h 中。

    函数 android_fork_execvp_ext() 的实现如下

    int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
            int log_target, bool abbreviated, char *file_path,
            const struct AndroidForkExecvpOption* opts, size_t opts_len) {
        // fork 一个新的进程运行 vdc 程序
        pid = fork();
        if (pid < 0) {
            .....
        } else if (pid == 0) {
            .....
            // fork 进程成功, 执行函数 child()
            child(argc, argv);
        } else {
    
    }
    

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

    static void child(int argc, char* argv[]) {
        // create null terminated argv_child array
        char* argv_child[argc + 1];
        memcpy(argv_child, argv, argc * sizeof(char *));
        argv_child[argc] = NULL;
        // 开始运行 vdc 程序,参数 cryptfs, enablefilecrypto
        // 从 init 进程,进入到 vdc 进程
        if (execvp(argv_child[0], argv_child)) {
            FATAL_CHILD("executing %s failed: %s\n", argv_child[0],
                    strerror(errno));
        }
    }
    

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

    int main(int argc, char **argv) {
        // 定义待连接的 socket 标识
        const char* sockname = "vold";
        //在上面的参数中 argv[1] 等于 cryptfs, 所以 socket name 等于 cryptd
        if (!strcmp(argv[1], "cryptfs")) {
            sockname = "cryptd";
        }
        // 等待连接到 vold
        while ((sock = socket_local_client(sockname,
                                     ANDROID_SOCKET_NAMESPACE_RESERVED,
                                     SOCK_STREAM)) < 0) {
            .....
        }
        if (!strcmp(argv[1], "monitor")) {
            exit(do_monitor(sock, 0));
        } else {
            //argv[1] 等于 cryptfs, 执行函数 do_cmd()
            exit(do_cmd(sock, argc, argv));
        }
    }
    

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

    static int do_cmd(int sock, int argc, char **argv) {
        .....
        // 写入 socket,注意参数 cmd.c_str()
        if ((write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
            fprintf(stderr, "Failed to write command: %s\n", strerror(errno));
            return errno;
        }
        return do_monitor(sock, seq);
    }
    

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

    socket 写入数据到远程后,执行到 vold 进程

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

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

    函数 cryptfs_enable_file() 定义如下

    int cryptfs_enable_file()
    {
        return e4crypt_initialize_global_de();
    }
    

    这个函数定义在文件 system/vold/cryptfs.c 中。

    bool e4crypt_initialize_global_de() {
        .....
        // device_key_path = /data/unencrypted/key/
        if (path_exists(device_key_path)) {
            if (!android::vold::retrieveKey(device_key_path,
                    kEmptyAuthentication, &device_key)) return false;
        } else {
            LOG(INFO) << "Creating new key";
            // 创建 密钥
            if (!random_key(&device_key)) return false;
            // 保存密钥
            if (!store_key(device_key_path, device_key_temp,
                    kEmptyAuthentication, device_key)) return false;
        }
    
        std::string device_key_ref;
        //存储在密钥代码库中
        if (!install_key(device_key, &device_key_ref)) {
            LOG(ERROR) << "Failed to install device key";
            return false;
        }
        // 应用密钥
        std::string ref_filename = std::string("/data") + e4crypt_key_ref;
        if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
            PLOG(ERROR) << "Cannot save key reference";
            return false;
        }
    
        s_global_de_initialized = true;
        return true;
    }
    

    DE密钥创建过程就分析到这里。

    CE密钥

    同样在 init.rc 的 post-fs-data action 中

    on post-fs-data
        .....
        installkey /data
        .....
        执行 init_user0 命令
        init_user0
        .....
    

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

    init_user0 实质是执行函数

    BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        static const Map builtin_functions = {
        .....
        {"ifup",                    {1,     1,    do_ifup}},
        //执行 do_init_user0() 函数
        {"init_user0",              {0,     0,    do_init_user0}},
        .....
    }
    

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

    函数 do_init_user0() 定义如下

    static int do_init_user0(const std::vector<std::string>& args) {
        //直接调用了函数 e4crypt_do_init_user0()
        return e4crypt_do_init_user0();
    }
    

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

    函数 e4crypt_do_init_user0() 定义如下

    int e4crypt_do_init_user0()
    {
        init_logging();
        //执行 vdc , 参数 cryptfs 和 init_user0, 和 DE 的创建过程类似
        const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "init_user0" };
        // fork vdc 进程,并运行 vdc 程序
        int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
        LOG(INFO) << "init_user0 result: " << rc;
        return rc;
    }
    

    这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。

    函数 android_fork_execvp() 运行 vdc 后,vdc 并没有做什么具体的操作,只是把相应的参数继续传递给 vold,和 DE 的密钥创建过程一样,参数 "cryptfs" 和 参数 "init_user0" 决定会执行到 vold 的如下代码

    int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
                                                     int argc, char **argv) {    
        .....
        } else if (subcommand == "init_user0") {
            if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
            //执行函数 e4crypt_init_user0()
            return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
        .....
    }
    

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

    函数 e4crypt_init_user0() 定义如下

    bool e4crypt_init_user0() {
        LOG(DEBUG) << "e4crypt_init_user0";
        if (e4crypt_is_native()) {
            // user_key_dir 等于 data/misc/vold/user_keys
            if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
            if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
            if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
            if (!path_exists(get_de_key_path(0))) {
                //创建和安装 CD keys, user 为 0, 即开机默认的 user
                if (!create_and_install_user_keys(0, false)) return false;
            }
            // TODO: switch to loading only DE_0 here once framework makes
            // explicit calls to install DE keys for secondary users
            if (!load_all_de_keys()) return false;
        }
        // We can only safely prepare DE storage here, since CE keys are probably
        // entangled with user credentials.  The framework will always prepare CE
        // storage once CE keys are installed.
        if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
            LOG(ERROR) << "Failed to prepare user 0 storage";
            return false;
        }
    
        // If this is a non-FBE device that recently left an emulated mode,
        // restore user data directories to known-good state.
        if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
            e4crypt_unlock_user_key(0, 0, "!", "!");
        }
    
        return true;
    }
    

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

    函数 create_and_install_user_keys() 定义如下

    static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
        std::string de_key, ce_key;
        //创建 DE 密钥
        if (!random_key(&de_key)) return false;
        //创建 CE 密钥
        if (!random_key(&ce_key)) return false;
        .....
        std::string de_raw_ref;
        // 存储 DE 密钥到密钥代码库
        if (!install_key(de_key, &de_raw_ref)) return false;
        s_de_key_raw_refs[user_id] = de_raw_ref;
        std::string ce_raw_ref;
        // 存储 CE 密钥到密钥代码库
        if (!install_key(ce_key, &ce_raw_ref)) return false;
        s_ce_keys[user_id] = ce_key;
        s_ce_key_raw_refs[user_id] = ce_raw_ref;
        LOG(DEBUG) << "Created keys for user " << user_id;
        return true;
    }
    

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

    再看看密钥的真正生成过程 random_key()

    static bool random_key(std::string* key) {
        // 读取随机密钥
        if (android::vold::ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
            // TODO status_t plays badly with PLOG, fix it.
            LOG(ERROR) << "Random read failed";
            return false;
        }
        return true;
    }
    

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

    ReadRandomBytes() 定义如下

    status_t ReadRandomBytes(size_t bytes, std::string& out) {
        out.clear();
        //打开 linux 的随机数文件
        int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
        if (fd == -1) {
            return -errno;
        }
    
        char buf[BUFSIZ];
        size_t n;
        //读取一个随机数,作为密钥
        while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
            out.append(buf, n);
            bytes -= n;
        }
        close(fd);
    
        if (bytes == 0) {
            return OK;
        } else {
            return -EIO;
        }
    }
    

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

    使用创建的密钥加密

    在解析 init.rc 文件时,会执行命令 mkdir, 如

    mkdir /data/system_de 0770 system system
    on post-fs-data
        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
        // 用户 DE 空间
        mkdir /data/user_de 0711 system system
        // /data/data 连接到目录 /data/user/0
        // /data/user 和 /data/data 都是 CE 空间
        symlink /data/data /data/user/0
    

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

    命令 mkdir 实质执行的的是函数 do_mkdir()

    BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        static const Map builtin_functions = {
        .....
        {"mkdir",                   {1,     4,    do_mkdir}},
        .....
    }
    

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

    函数 do_mkdir() 的实现如下

    static int do_mkdir(const std::vector<std::string>& args) {
        .....
        // 创建目录
        ret = make_dir(args[1].c_str(), mode);
        .....
        if (e4crypt_is_native()) {
            // 加密目录
            if (e4crypt_set_directory_policy(args[1].c_str())) {
                wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
                return -1;
            }
        }
        return 0;
    }
    

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

    函数 e4crypt_set_directory_policy() 的实现如下

    int e4crypt_set_directory_policy(const char* dir)
    {
        // 只加密 /data 目录以及子目录
        if (!dir || strncmp(dir, "/data/", 6) || strchr(dir + 6, '/')) {
            return 0;
        }
    
        // 不需要加密的目录在这里设置,但是,它们的子目录是会被加密的
        std::vector<std::string> directories_to_exclude = {
            "lost+found",
            "system_ce", "system_de",
            "misc_ce", "misc_de",
            "media",
            "data", "user", "user_de",
        };
        std::string prefix = "/data/";
        for (auto d: directories_to_exclude) {
            if ((prefix + d) == dir) {
                KLOG_INFO(TAG, "Not setting policy on %s\n", dir);
                return 0;
            }
        }
        // 密钥引用
        std::string ref_filename = std::string("/data") + e4crypt_key_ref;
        std::string policy;
        if (!android::base::ReadFileToString(ref_filename, &policy)) {
            KLOG_ERROR(TAG, "Unable to read system policy to set on %s\n", dir);
            return -1;
        }
        KLOG_INFO(TAG, "Setting policy on %s\n", dir);
        // 加密目录
        int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.size());
        if (result) {
            KLOG_ERROR(TAG, "Setting %02x%02x%02x%02x policy on %s failed!\n",
                       policy[0], policy[1], policy[2], policy[3], dir);
            return -1;
        }
    
        return 0;
    }
    

    这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。

    函数 e4crypt_policy_ensure() 定义如下

    int e4crypt_policy_ensure(const char *directory, const char *policy, size_t policy_length) {
        bool is_empty;
        if (!is_dir_empty(directory, &is_empty)) return -1;
        if (is_empty) {
            // 应用加密政策
            if (!e4crypt_policy_set(directory, policy, policy_length)) return -1;
        } else {
            if (!e4crypt_policy_check(directory, policy, policy_length)) return -1;
        }
        return 0;
    }
    

    这个方法定义在文件 system/extras/ext4_utils/ext4_crypt.cpp 中。

    函数 e4crypt_policy_set() 定义如下

    static bool e4crypt_policy_set(const char *directory, const char *policy, size_t policy_length) {
        int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
        ......
        ext4_encryption_policy eep;
        eep.version = 0;
        // 设置加密类型 AES 256
        eep.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
        eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
        eep.flags = 0;
        memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
        // 用命令 EXT4_IOC_SET_ENCRYPTION_POLICY 控制 IO
        if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
            PLOG(ERROR) << "Failed to set encryption policy for " << directory;
            close(fd);
            return false;
        }
        close(fd);
    
        char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
        policy_to_hex(policy, policy_hex);
        LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
        return true;
    }
    

    这个方法定义在文件 system/extras/ext4_utils/ext4_crypt.cpp 中。

    加密过程就分析到这里。

    直接启动

    应用了文件级加密的设备,可以以直接启动的方式启动。此时,设备可以加载并使用没有通过文件级加密的目录,如 /data/user_de/0/。那么,直接启动的 APP 的数据保存在这个目录下。

    在上文中,我们知道需要在直接启动就可以立马使用的的 APP,需要在应用的 manifest 的 application 标签声明 android:directBootAware="true" 属性。对于系统的应用,声明 android:defaultToDeviceProtectedStorage="true" 可以把应用的默认存储空间设置为 /data/user_de/。

    因此,在用户没有输入凭据解密 CE 空间之前,系统只是加载 DE 下的应用。

    在 AMS ready 时,如下(读者不了解这个过程的以看考文章《 Android系统之System Server大纲》

    public void systemReady(final Runnable goingCallback) {
        .....
        synchronized (this) {
            // Only start up encryption-aware persistent apps; once user is
            // unlocked we'll come back around and start unaware apps
            //启动 persistent app,注意参数 PackageManager.MATCH_DIRECT_BOOT_AWARE
            startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
        }
        .....
    

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

    方法 startPersistentApps() 的实现如下

    private void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
    
        synchronized (this) {
            try {
                //获取所有 direct boot 的 app
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    if (!"android".equals(app.packageName) && validNewProc(app.packageName, UserHandle.getUserId(app.uid))) {//modified by yongfeng.zhang for task 3682193 on 2016-12-28
                        // 加入启动队列
                        addAppLocked(app, false, null /* ABI override */);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }
    

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

    方法 addAppLocked() 定义如下

    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
            String abiOverride) {
        .....
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            mPersistentStartingProcesses.add(app);
            // 启动 APP
            startProcessLocked(app, "added application", app.processName, abiOverride,
                    null /* entryPoint */, null /* entryPointArgs */);
        }
        return app;
    }
    

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

    在 PMS 启动时,扫描安装 APP 是,会过滤不是直接启动的 APP

    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
            final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
        // Apply policy
        if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
            //直接启动的 APP
            if (pkg.applicationInfo.isDirectBootAware()) {
                // we're direct boot aware; set for all components
                for (PackageParser.Service s : pkg.services) {
                    s.info.encryptionAware = s.info.directBootAware = true;
                }
                for (PackageParser.Provider p : pkg.providers) {
                    p.info.encryptionAware = p.info.directBootAware = true;
                }
                for (PackageParser.Activity a : pkg.activities) {
                    a.info.encryptionAware = a.info.directBootAware = true;
                }
                for (PackageParser.Activity r : pkg.receivers) {
                    r.info.encryptionAware = r.info.directBootAware = true;
                }
            }
        }
    
    }
    

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

    总结

    文件级加密,比较全盘加密具有一些优点,可以让没有输入凭证的设备可以使用更多的功能。文件级加密分 CE 空间和 DE 空间,CE 空间需要凭证加密方可使用,DE 空间则是设备启动后即可使用。应用如果需要区分 CE 和 DE 空间,需要创建不同的上下文环境 Context。

    相关文章

      网友评论

        本文标题:Android加密之文件级加密

        本文链接:https://www.haomeiwen.com/subject/xualrxtx.html