diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 1f7faac..21495be 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -208,6 +208,19 @@ static bool get_data_file_encryption_options(EncryptionOptions* options) { return true; } +static bool install_storage_key(const std::string& mountpoint, const EncryptionOptions& options, + const KeyBuffer& key, EncryptionPolicy* policy) { + KeyBuffer ephemeral_wrapped_key; + if (options.use_hw_wrapped_key) { + if (!exportWrappedStorageKey(key, &ephemeral_wrapped_key)) { + LOG(ERROR) << "Failed to get ephemeral wrapped key"; + return false; + } + } + return installKey(mountpoint, options, options.use_hw_wrapped_key ? ephemeral_wrapped_key : key, + policy); +} + // Retrieve the options to use for encryption policies on adoptable storage. static bool get_volume_file_encryption_options(EncryptionOptions* options) { auto contents_mode = @@ -231,7 +244,7 @@ static bool read_and_install_user_ce_key(userid_t user_id, KeyBuffer ce_key; if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false; EncryptionPolicy ce_policy; - if (!installKey(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false; + if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false; s_ce_policies[user_id] = ce_policy; LOG(DEBUG) << "Installed ce key for user " << user_id; return true; @@ -261,8 +274,8 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral EncryptionOptions options; if (!get_data_file_encryption_options(&options)) return false; KeyBuffer de_key, ce_key; - if (!android::vold::randomKey(&de_key)) return false; - if (!android::vold::randomKey(&ce_key)) return false; + if (!generateStorageKey(options, &de_key)) return false; + if (!generateStorageKey(options, &ce_key)) return false; if (create_ephemeral) { // If the key should be created as ephemeral, don't store it. s_ephemeral_users.insert(user_id); @@ -282,10 +295,10 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral return false; } EncryptionPolicy de_policy; - if (!installKey(DATA_MNT_POINT, options, de_key, &de_policy)) return false; + if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false; s_de_policies[user_id] = de_policy; EncryptionPolicy ce_policy; - if (!installKey(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false; + if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false; s_ce_policies[user_id] = ce_policy; LOG(DEBUG) << "Created keys for user " << user_id; return true; @@ -338,7 +351,7 @@ static bool load_all_de_keys() { KeyBuffer de_key; if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; EncryptionPolicy de_policy; - if (!installKey(DATA_MNT_POINT, options, de_key, &de_policy)) return false; + if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false; s_de_policies[user_id] = de_policy; LOG(DEBUG) << "Installed de key for user " << user_id; } @@ -360,12 +373,11 @@ bool fscrypt_initialize_systemwide_keys() { KeyBuffer device_key; if (!android::vold::retrieveKey(true, kEmptyAuthentication, device_key_path, device_key_temp, - &device_key)) + options, &device_key)) return false; EncryptionPolicy device_policy; - if (!android::vold::installKey(DATA_MNT_POINT, options, device_key, &device_policy)) - return false; + if (!install_storage_key(DATA_MNT_POINT, options, device_key, &device_policy)) return false; std::string options_string; if (!OptionsToString(device_policy.options, &options_string)) { @@ -380,10 +392,9 @@ bool fscrypt_initialize_systemwide_keys() { LOG(INFO) << "Wrote system DE key reference to:" << ref_filename; KeyBuffer per_boot_key; - if (!android::vold::randomKey(&per_boot_key)) return false; + if (!generateStorageKey(options, &per_boot_key)) return false; EncryptionPolicy per_boot_policy; - if (!android::vold::installKey(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) - return false; + if (!install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) return false; std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref; if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename)) return false; @@ -590,8 +601,9 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin EncryptionOptions options; if (!get_volume_file_encryption_options(&options)) return false; KeyBuffer key; - if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", &key)) return false; - if (!android::vold::installKey(BuildDataPath(volume_uuid), options, key, policy)) return false; + if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", options, &key)) + return false; + if (!install_storage_key(BuildDataPath(volume_uuid), options, key, policy)) return false; return true; } diff --git a/KeyStorage.cpp b/KeyStorage.cpp index dbf190d..a7582c2 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -135,6 +135,30 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& keymaster.generateKey(paramBuilder, key); } +bool generateWrappedStorageKey(KeyBuffer* key) { + Keymaster keymaster; + if (!keymaster) return false; + std::string key_temp; + auto paramBuilder = km::AuthorizationSetBuilder().AesEncryptionKey(AES_KEY_BYTES * 8); + paramBuilder.Authorization(km::TAG_ROLLBACK_RESISTANCE); + paramBuilder.Authorization(km::TAG_STORAGE_KEY); + if (!keymaster.generateKey(paramBuilder, &key_temp)) return false; + *key = KeyBuffer(key_temp.size()); + memcpy(reinterpret_cast(key->data()), key_temp.c_str(), key->size()); + return true; +} + +bool exportWrappedStorageKey(const KeyBuffer& kmKey, KeyBuffer* key) { + Keymaster keymaster; + if (!keymaster) return false; + std::string key_temp; + + if (!keymaster.exportKey(kmKey, &key_temp)) return false; + *key = KeyBuffer(key_temp.size()); + memcpy(reinterpret_cast(key->data()), key_temp.c_str(), key->size()); + return true; +} + static std::pair beginParams( const KeyAuthentication& auth, const std::string& appId) { auto paramBuilder = km::AuthorizationSetBuilder() diff --git a/KeyStorage.h b/KeyStorage.h index 276b6b9..f9d3ec6 100644 --- a/KeyStorage.h +++ b/KeyStorage.h @@ -68,6 +68,11 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe bool destroyKey(const std::string& dir); bool runSecdiscardSingle(const std::string& file); + +// Generate wrapped storage key using keymaster. Uses STORAGE_KEY tag in keymaster. +bool generateWrappedStorageKey(KeyBuffer* key); +// Export the per-boot boot wrapped storage key using keymaster. +bool exportWrappedStorageKey(const KeyBuffer& kmKey, KeyBuffer* key); } // namespace vold } // namespace android diff --git a/KeyUtil.cpp b/KeyUtil.cpp index d4a653b..ae4d70b 100644 --- a/KeyUtil.cpp +++ b/KeyUtil.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "KeyStorage.h" #include "Utils.h" @@ -45,6 +46,13 @@ bool randomKey(KeyBuffer* key) { return true; } +bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key) { + if (options.use_hw_wrapped_key) { + return generateWrappedStorageKey(key); + } + return randomKey(key); +} + // Return true if the kernel supports the ioctls to add/remove fscrypt keys // directly to/from the filesystem. bool isFsKeyringSupported(void) { @@ -222,6 +230,7 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options, return false; } + if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED; // Provide the raw key. arg->raw_size = key.size(); memcpy(arg->raw, key.data(), key.size()); @@ -307,8 +316,8 @@ bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) { } bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication, - const std::string& key_path, const std::string& tmp_path, KeyBuffer* key, - bool keepOld) { + const std::string& key_path, const std::string& tmp_path, + const EncryptionOptions& options, KeyBuffer* key, bool keepOld) { if (pathExists(key_path)) { LOG(DEBUG) << "Key exists, using: " << key_path; if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false; @@ -318,7 +327,7 @@ bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authenticat return false; } LOG(INFO) << "Creating new key in " << key_path; - if (!randomKey(key)) return false; + if (!generateStorageKey(options, key)) return false; if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false; } return true; diff --git a/KeyUtil.h b/KeyUtil.h index be5a2ed..878b4ab 100644 --- a/KeyUtil.h +++ b/KeyUtil.h @@ -32,6 +32,8 @@ using namespace android::fscrypt; bool randomKey(KeyBuffer* key); +bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key); + bool isFsKeyringSupported(void); // Install a file-based encryption key to the kernel, for use by encrypted files @@ -57,8 +59,8 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options, bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy); bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication, - const std::string& key_path, const std::string& tmp_path, KeyBuffer* key, - bool keepOld = true); + const std::string& key_path, const std::string& tmp_path, + const EncryptionOptions& options, KeyBuffer* key, bool keepOld = true); } // namespace vold } // namespace android diff --git a/Keymaster.cpp b/Keymaster.cpp index abee9b2..c3f2912 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -138,6 +138,27 @@ bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* k return true; } +bool Keymaster::exportKey(const KeyBuffer& kmKey, std::string* key) { + auto kmKeyBlob = km::support::blob2hidlVec(std::string(kmKey.data(), kmKey.size())); + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& exportedKeyBlob) { + km_error = ret; + if (km_error != km::ErrorCode::OK) return; + if (key) + key->assign(reinterpret_cast(&exportedKeyBlob[0]), exportedKeyBlob.size()); + }; + auto error = mDevice->exportKey(km::KeyFormat::RAW, kmKeyBlob, {}, {}, hidlCb); + if (!error.isOk()) { + LOG(ERROR) << "export_key failed: " << error.description(); + return false; + } + if (km_error != km::ErrorCode::OK) { + LOG(ERROR) << "export_key failed, code " << int32_t(km_error); + return false; + } + return true; +} + bool Keymaster::deleteKey(const std::string& key) { auto keyBlob = km::support::blob2hidlVec(key); auto error = mDevice->deleteKey(keyBlob); diff --git a/Keymaster.h b/Keymaster.h index 8ddd8f7..ea102f5 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -114,6 +114,8 @@ class Keymaster { explicit operator bool() { return mDevice.get() != nullptr; } // Generate a key in the keymaster from the given params. bool generateKey(const km::AuthorizationSet& inParams, std::string* key); + // Exports a keymaster key with STORAGE_KEY tag wrapped with a per-boot ephemeral key + bool exportKey(const KeyBuffer& kmKey, std::string* key); // If the keymaster supports it, permanently delete a key. bool deleteKey(const std::string& key); // Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE. diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index acd5b59..76ea9eb 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -113,6 +113,23 @@ static void commit_key(const std::string& dir) { LOG(INFO) << "Old Key deleted: " << dir; } +static bool retrieveMetadataKey(bool create_if_absent, const std::string& key_path, + const std::string& tmp_path, KeyBuffer* key, bool keepOld) { + if (pathExists(key_path)) { + LOG(DEBUG) << "Key exists, using: " << key_path; + if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false; + } else { + if (!create_if_absent) { + LOG(ERROR) << "No key found in " << key_path; + return false; + } + LOG(INFO) << "Creating new key in " << key_path; + if (!randomKey(key)) return false; + if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false; + } + return true; +} + static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffer* key) { if (data_rec.metadata_key_dir.empty()) { LOG(ERROR) << "Failed to get metadata_key_dir"; @@ -143,9 +160,7 @@ static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffe unlink(newKeyPath.c_str()); } bool needs_cp = cp_needsCheckpoint(); - if (!android::vold::retrieveKey(create_if_absent, kEmptyAuthentication, dir, temp, key, - needs_cp)) - return false; + if (!retrieveMetadataKey(create_if_absent, dir, temp, key, needs_cp)) return false; if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach(); return true; } diff --git a/fscrypt_uapi.h b/fscrypt_uapi.h new file mode 100644 index 0000000..08592e0 --- /dev/null +++ b/fscrypt_uapi.h @@ -0,0 +1,19 @@ +#ifndef _UAPI_LINUX_FSCRYPT_VOLD_H +#define _UAPI_LINUX_FSCRYPT_VOLD_H + +#include +#include + +#define FSCRYPT_ADD_KEY_FLAG_WRAPPED 0x01 + +struct sys_fscrypt_add_key_arg { + struct fscrypt_key_specifier key_spec; + __u32 raw_size; + __u32 __reserved[8]; + __u32 flags; + __u8 raw[]; +}; + +#define fscrypt_add_key_arg sys_fscrypt_add_key_arg + +#endif //_UAPI_LINUX_FSCRYPT_VOLD_H