From 79f88bdf8d54a84b7bb727b0c28b2dfcdc3d14d5 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Fri, 9 Dec 2016 14:52:12 -0600 Subject: Support backup/restore of FBE policies Change-Id: Iba8ef20f57b0fb57bb9406c53148a806441d0b59 --- crypto/ext4crypt/Android.mk | 13 ++- crypto/ext4crypt/Decrypt.cpp | 62 ++++++++++++++ crypto/ext4crypt/Ext4Crypt.cpp | 12 ++- crypto/ext4crypt/Ext4Crypt.h | 4 + crypto/ext4crypt/e4policyget.cpp | 44 ++++++++++ crypto/ext4crypt/ext4_crypt.cpp | 180 +++++++++++++++++++++++++++++++++++++++ crypto/ext4crypt/ext4crypt_tar.h | 38 +++++++++ 7 files changed, 348 insertions(+), 5 deletions(-) create mode 100644 crypto/ext4crypt/e4policyget.cpp create mode 100644 crypto/ext4crypt/ext4_crypt.cpp create mode 100644 crypto/ext4crypt/ext4crypt_tar.h (limited to 'crypto') diff --git a/crypto/ext4crypt/Android.mk b/crypto/ext4crypt/Android.mk index 531aca199..bcbcccfa2 100644 --- a/crypto/ext4crypt/Android.mk +++ b/crypto/ext4crypt/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := libe4crypt LOCAL_MODULE_TAGS := eng optional LOCAL_CFLAGS := -LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp +LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils libsoftkeymaster libbase libcrypto libcutils libkeymaster_messages libhardware libprotobuf-cpp-lite LOCAL_STATIC_LIBRARIES := libscrypt_static LOCAL_C_INCLUDES := system/extras/ext4_utils external/scrypt/lib/crypto system/security/keystore hardware/libhardware/include/hardware system/security/softkeymaster/include/keymaster system/keymaster/include @@ -30,4 +30,15 @@ LOCAL_SHARED_LIBRARIES := libe4crypt include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) +LOCAL_MODULE := e4policyget +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_SRC_FILES := e4policyget.cpp +LOCAL_SHARED_LIBRARIES := libe4crypt +LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64 + +include $(BUILD_EXECUTABLE) + endif diff --git a/crypto/ext4crypt/Decrypt.cpp b/crypto/ext4crypt/Decrypt.cpp index 6c47add0c..3b69d4651 100644 --- a/crypto/ext4crypt/Decrypt.cpp +++ b/crypto/ext4crypt/Decrypt.cpp @@ -17,10 +17,12 @@ #include "Decrypt.h" #include "Ext4Crypt.h" +#include #include #include #include +#include #include #include @@ -32,6 +34,66 @@ #include +// Store main DE raw ref / policy +extern std::string de_raw_ref; +extern std::map s_de_key_raw_refs; +extern std::map s_ce_key_raw_refs; + +static bool lookup_ref_key_internal(std::map& key_map, const char* policy, userid_t* user_id) { + for (std::map::iterator it=key_map.begin(); it!=key_map.end(); ++it) { + if (strncmp(it->second.c_str(), policy, it->second.size()) == 0) { + *user_id = it->first; + return true; + } + } + return false; +} + +extern "C" bool lookup_ref_key(const char* policy, char* policy_type) { + userid_t user_id = 0; + if (strncmp(de_raw_ref.c_str(), policy, de_raw_ref.size()) == 0) { + strcpy(policy_type, "1DK"); + return true; + } + if (!lookup_ref_key_internal(s_de_key_raw_refs, policy, &user_id)) { + if (!lookup_ref_key_internal(s_ce_key_raw_refs, policy, &user_id)) { + return false; + } else + sprintf(policy_type, "1CE%d", user_id); + } else + sprintf(policy_type, "1DE%d", user_id); + return true; +} + +extern "C" bool lookup_ref_tar(const char* policy_type, char* policy) { + if (strncmp(policy_type, "1", 1) != 0) { + printf("Unexpected version %c\n", policy_type); + return false; + } + const char* ptr = policy_type + 1; // skip past the version number + if (strncmp(ptr, "DK", 2) == 0) { + strncpy(policy, de_raw_ref.data(), de_raw_ref.size()); + return true; + } + userid_t user_id = atoi(ptr + 2); + std::string raw_ref; + if (*ptr == 'D') { + if (lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref)) { + strncpy(policy, raw_ref.data(), raw_ref.size()); + } else + return false; + } else if (*ptr == 'C') { + if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) { + strncpy(policy, raw_ref.data(), raw_ref.size()); + } else + return false; + } else { + printf("unknown policy type '%s'\n", policy_type); + return false; + } + return true; +} + int gatekeeper_device_initialize(gatekeeper_device_t **dev) { int ret; const hw_module_t *mod; diff --git a/crypto/ext4crypt/Ext4Crypt.cpp b/crypto/ext4crypt/Ext4Crypt.cpp index 423147d66..8bc419992 100644 --- a/crypto/ext4crypt/Ext4Crypt.cpp +++ b/crypto/ext4crypt/Ext4Crypt.cpp @@ -67,6 +67,12 @@ using android::vold::kEmptyAuthentication; //static constexpr int FLAG_STORAGE_DE = 1 << 0; // moved to Decrypt.h //static constexpr int FLAG_STORAGE_CE = 1 << 1; +// Store main DE raw ref / policy +std::string de_raw_ref; +// Map user ids to key references +std::map s_de_key_raw_refs; +std::map s_ce_key_raw_refs; + namespace { const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder; const std::string device_key_path = device_key_dir + "/key"; @@ -80,9 +86,6 @@ bool s_global_de_initialized = false; // Some users are ephemeral, don't try to wipe their keys from disk std::set s_ephemeral_users; -// Map user ids to key references -std::map s_de_key_raw_refs; -std::map s_ce_key_raw_refs; // TODO abolish this map. Keys should not be long-lived in user memory, only kernel memory. // See b/26948053 std::map s_ce_keys; @@ -290,7 +293,7 @@ static bool path_exists(const std::string& path) { return access(path.c_str(), F_OK) == 0; } -static bool lookup_key_ref(const std::map& key_map, userid_t user_id, +bool lookup_key_ref(const std::map& key_map, userid_t user_id, std::string* raw_ref) { auto refi = key_map.find(user_id); if (refi == key_map.end()) { @@ -379,6 +382,7 @@ bool e4crypt_initialize_global_de() { } s_global_de_initialized = true; + de_raw_ref = device_key_ref; return true; } diff --git a/crypto/ext4crypt/Ext4Crypt.h b/crypto/ext4crypt/Ext4Crypt.h index b05ff4ddb..57623e35c 100644 --- a/crypto/ext4crypt/Ext4Crypt.h +++ b/crypto/ext4crypt/Ext4Crypt.h @@ -19,6 +19,7 @@ #include +#include #include __BEGIN_DECLS @@ -40,4 +41,7 @@ bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token, co bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial, int flags); //bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags); +bool lookup_key_ref(const std::map& key_map, userid_t user_id, + std::string* raw_ref); + __END_DECLS diff --git a/crypto/ext4crypt/e4policyget.cpp b/crypto/ext4crypt/e4policyget.cpp new file mode 100644 index 000000000..d217f18ee --- /dev/null +++ b/crypto/ext4crypt/e4policyget.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Team Win Recovery Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "ext4crypt_tar.h" + +#define EXT4_KEY_DESCRIPTOR_SIZE 8 +#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 + +int main(int argc, char *argv[]) { + bool ret = false; + if (argc != 2) { + printf("Must specify a path\n"); + return -1; + } else { + char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE]; + if (e4crypt_policy_get(argv[1], e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0)) + { + char* ptr = tar_policy; + memset(tar_policy, 0, sizeof(tar_policy)); + char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; + policy_to_hex(e4crypt_policy, policy_hex); + printf("%s\n", policy_hex); + } else { + printf("No policy set\n"); + } + } + return 0; +} diff --git a/crypto/ext4crypt/ext4_crypt.cpp b/crypto/ext4crypt/ext4_crypt.cpp new file mode 100644 index 000000000..029db7567 --- /dev/null +++ b/crypto/ext4crypt/ext4_crypt.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* TWRP NOTE: Kanged from system/extras/ext4_utils/ext4_crypt.cpp + * because policy_to_hex, e4crypt_policy_set, and e4crypt_policy_get + * are not exposed to be used. There was also a bug in e4crypt_policy_get + * that may or may not be fixed in the user's local repo: + * https://android.googlesource.com/platform/system/extras/+/30b93dd5715abcabd621235733733c0503f9c552 + */ + +#include "ext4_crypt.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy" +#define EXT4_KEYREF_DELIMITER ((char)'.') + +// ext4enc:TODO Include structure from somewhere sensible +// MUST be in sync with ext4_crypto.c in kernel +#define EXT4_KEY_DESCRIPTOR_SIZE 8 +#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 + +struct ext4_encryption_policy { + char version; + char contents_encryption_mode; + char filenames_encryption_mode; + char flags; + char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; +} __attribute__((__packed__)); + +#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 +#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 +#define EXT4_ENCRYPTION_MODE_PRIVATE 127 + +static int encryption_mode = EXT4_ENCRYPTION_MODE_PRIVATE; + +// ext4enc:TODO Get value from somewhere sensible +#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) +#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) + +#define HEX_LOOKUP "0123456789abcdef" + +extern "C" void policy_to_hex(const char* policy, char* hex) { + for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) { + hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4]; + hex[j++] = HEX_LOOKUP[policy[i] & 0x0F]; + } + hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0'; +} + +extern "C" bool e4crypt_policy_set(const char *directory, const char *policy, + size_t policy_length, int contents_encryption_mode) { + if (contents_encryption_mode == 0) + contents_encryption_mode = encryption_mode; + if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { + printf("policy wrong length\n"); + LOG(ERROR) << "Policy wrong length: " << policy_length; + return false; + } + int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (fd == -1) { + printf("failed to open %s\n", directory); + PLOG(ERROR) << "Failed to open directory " << directory; + return false; + } + + ext4_encryption_policy eep; + eep.version = 0; + eep.contents_encryption_mode = contents_encryption_mode; + eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS; + eep.flags = 0; + memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE); + if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) { + printf("failed to set policy for '%s' '%s'\n", directory, policy); + 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; +} + +extern "C" bool e4crypt_policy_get(const char *directory, char *policy, + size_t policy_length, int contents_encryption_mode) { + if (contents_encryption_mode == 0) + contents_encryption_mode = encryption_mode; + if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { + LOG(ERROR) << "Policy wrong length: " << policy_length; + return false; + } + + int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (fd == -1) { + PLOG(ERROR) << "Failed to open directory " << directory; + return false; + } + + ext4_encryption_policy eep; + memset(&eep, 0, sizeof(ext4_encryption_policy)); + if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) { + PLOG(ERROR) << "Failed to get encryption policy for " << directory; + close(fd); + return false; + } + close(fd); + + if ((eep.version != 0) + || (eep.contents_encryption_mode != contents_encryption_mode) + || (eep.filenames_encryption_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) + || (eep.flags != 0)) { + LOG(ERROR) << "Failed to find matching encryption policy for " << directory; + return false; + } + memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE); + + return true; +} + +extern "C" bool e4crypt_set_mode() { + const char* mode_file = "/data/unencrypted/mode"; + struct stat st; + if (stat(mode_file, &st) != 0 || st.st_size <= 0) { + printf("Invalid encryption mode file %s\n", mode_file); + return false; + } + size_t mode_size = st.st_size; + char contents_encryption_mode[mode_size + 1]; + memset((void*)contents_encryption_mode, 0, mode_size + 1); + int fd = open(mode_file, O_RDONLY); + if (fd < 0) { + printf("error opening '%s': %s\n", mode_file, strerror(errno)); + return false; + } + if (read(fd, contents_encryption_mode, mode_size) != mode_size) { + printf("read error on '%s': %s\n", mode_file, strerror(errno)); + close(fd); + return false; + } + close(fd); + if (!strcmp(contents_encryption_mode, "software")) { + encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; + } else if (!strcmp(contents_encryption_mode, "ice")) { + encryption_mode = EXT4_ENCRYPTION_MODE_PRIVATE; + } else { + printf("Invalid encryption mode '%s'\n", contents_encryption_mode); + return false; + } + printf("set encryption mode to %i\n", encryption_mode); + return true; +} diff --git a/crypto/ext4crypt/ext4crypt_tar.h b/crypto/ext4crypt/ext4crypt_tar.h new file mode 100644 index 000000000..1c9cef0a5 --- /dev/null +++ b/crypto/ext4crypt/ext4crypt_tar.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Team Win Recovery Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __EXT4CRYPT_TAR_H +#define __EXT4CRYPT_TAR_H + +#include +#include +#include + +__BEGIN_DECLS + +bool lookup_ref_key(const char* policy, char* policy_type); +bool lookup_ref_tar(const char* policy_type, char* policy); + +void policy_to_hex(const char* policy, char* hex); +bool e4crypt_policy_set(const char *directory, const char *policy, + size_t policy_length, int contents_encryption_mode); +bool e4crypt_policy_get(const char *directory, char *policy, + size_t policy_length, int contents_encryption_mode); + +bool e4crypt_set_mode(); +__END_DECLS + +#endif -- cgit v1.2.3