From e2e2d308df2da26838de32852318bc2cb690d052 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Tue, 1 Aug 2017 17:15:53 +0100 Subject: [PATCH] Zero memory used for encryuption keys. std::vector with custom zeroing allocator is used instead of std::string for data that can contain encryption keys. Bug: 64201177 Test: manually created a managed profile, changed it's credentials Test: manually upgraded a phone with profile from O to MR1. Change-Id: Ic31877049f69eba9f8ea64fd99acaaca5a01d3dd --- Android.mk | 1 + Ext4Crypt.cpp | 17 +++++++------ KeyBuffer.cpp | 37 ++++++++++++++++++++++++++++ KeyBuffer.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++ KeyStorage.cpp | 16 ++++++------ KeyStorage.h | 8 +++--- KeyUtil.cpp | 32 ++++++++++++++++++------ KeyUtil.h | 23 +++++------------ Keymaster.cpp | 25 +++++++++---------- Keymaster.h | 15 ++++++++++- MetadataCrypt.cpp | 31 +++++++++++++---------- Utils.cpp | 19 +++++++++++--- Utils.h | 5 ++++ 13 files changed, 217 insertions(+), 75 deletions(-) create mode 100644 KeyBuffer.cpp create mode 100644 KeyBuffer.h diff --git a/Android.mk b/Android.mk index 9dba651..d0b199d 100644 --- a/Android.mk +++ b/Android.mk @@ -27,6 +27,7 @@ common_src_files := \ MoveTask.cpp \ Benchmark.cpp \ TrimTask.cpp \ + KeyBuffer.cpp \ Keymaster.cpp \ KeyStorage.cpp \ KeyUtil.cpp \ diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp index f9d4cf8..dc2e42a 100644 --- a/Ext4Crypt.cpp +++ b/Ext4Crypt.cpp @@ -57,6 +57,7 @@ using android::base::StringPrintf; using android::base::WriteStringToFile; using android::vold::kEmptyAuthentication; +using android::vold::KeyBuffer; // NOTE: keep in sync with StorageManager static constexpr int FLAG_STORAGE_DE = 1 << 0; @@ -80,7 +81,7 @@ std::set s_ephemeral_users; std::map s_de_key_raw_refs; std::map s_ce_key_raw_refs; // TODO abolish this map, per b/26948053 -std::map s_ce_keys; +std::map s_ce_keys; } @@ -170,7 +171,7 @@ static void fixate_user_ce_key(const std::string& directory_path, const std::str static bool read_and_fixate_user_ce_key(userid_t user_id, const android::vold::KeyAuthentication& auth, - std::string *ce_key) { + KeyBuffer *ce_key) { auto const directory_path = get_ce_key_directory_path(user_id); auto const paths = get_ce_key_paths(directory_path); for (auto const ce_key_path: paths) { @@ -188,11 +189,11 @@ static bool read_and_fixate_user_ce_key(userid_t user_id, static bool read_and_install_user_ce_key(userid_t user_id, const android::vold::KeyAuthentication& auth) { if (s_ce_key_raw_refs.count(user_id) != 0) return true; - std::string ce_key; + KeyBuffer ce_key; if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false; std::string ce_raw_ref; if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false; - s_ce_keys[user_id] = ce_key; + s_ce_keys[user_id] = std::move(ce_key); s_ce_key_raw_refs[user_id] = ce_raw_ref; LOG(DEBUG) << "Installed ce key for user " << user_id; return true; @@ -219,7 +220,7 @@ static bool destroy_dir(const std::string& dir) { // NB this assumes that there is only one thread listening for crypt commands, because // it creates keys in a fixed location. static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) { - std::string de_key, ce_key; + KeyBuffer de_key, ce_key; if (!android::vold::randomKey(&de_key)) return false; if (!android::vold::randomKey(&ce_key)) return false; if (create_ephemeral) { @@ -306,7 +307,7 @@ static bool load_all_de_keys() { userid_t user_id = atoi(entry->d_name); if (s_de_key_raw_refs.count(user_id) == 0) { auto key_path = de_dir + "/" + entry->d_name; - std::string key; + KeyBuffer key; if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &key)) return false; std::string raw_ref; if (!android::vold::installKey(key, &raw_ref)) return false; @@ -411,7 +412,7 @@ static void drop_caches() { } static bool evict_ce_key(userid_t user_id) { - s_ce_keys.erase(user_id); + s_ce_keys.erase(user_id); bool success = true; std::string raw_ref; // If we haven't loaded the CE key, no need to evict it. @@ -509,7 +510,7 @@ bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token_h LOG(ERROR) << "Key not loaded into memory, can't change for user " << user_id; return false; } - auto ce_key = it->second; + const auto &ce_key = it->second; auto const directory_path = get_ce_key_directory_path(user_id); auto const paths = get_ce_key_paths(directory_path); std::string ce_key_path; diff --git a/KeyBuffer.cpp b/KeyBuffer.cpp new file mode 100644 index 0000000..e7aede5 --- /dev/null +++ b/KeyBuffer.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "KeyBuffer.h" + +#include +#include + +namespace android { +namespace vold { + +KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs) { + std::copy(rhs.begin(), rhs.end(), std::back_inserter(lhs)); + return std::move(lhs); +} + +KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs) { + std::copy(rhs, rhs + strlen(rhs), std::back_inserter(lhs)); + return std::move(lhs); +} + +} // namespace vold +} // namespace android + diff --git a/KeyBuffer.h b/KeyBuffer.h new file mode 100644 index 0000000..2087187 --- /dev/null +++ b/KeyBuffer.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef ANDROID_VOLD_KEYBUFFER_H +#define ANDROID_VOLD_KEYBUFFER_H + +#include +#include +#include + +namespace android { +namespace vold { + +/** + * Variant of memset() that should never be optimized away. Borrowed from keymaster code. + */ +#ifdef __clang__ +#define OPTNONE __attribute__((optnone)) +#else // not __clang__ +#define OPTNONE __attribute__((optimize("O0"))) +#endif // not __clang__ +inline OPTNONE void* memset_s(void* s, int c, size_t n) { + if (!s) + return s; + return memset(s, c, n); +} +#undef OPTNONE + +// Allocator that delegates useful work to standard one but zeroes data before deallocating. +class ZeroingAllocator : public std::allocator { + public: + void deallocate(pointer p, size_type n) + { + memset_s(p, 0, n); + std::allocator::deallocate(p, n); + } +}; + +// Char vector that zeroes memory when deallocating. +using KeyBuffer = std::vector; + +// Convenience methods to concatenate key buffers. +KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs); +KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs); + +} // namespace vold +} // namespace android + +#endif + diff --git a/KeyStorage.cpp b/KeyStorage.cpp index b4f85f4..9d61555 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -195,7 +195,7 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, const AuthorizationSet &keyParams, - const std::string& message, std::string* ciphertext) { + const KeyBuffer& message, std::string* ciphertext) { AuthorizationSet opParams; AuthorizationSet outParams; auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams); @@ -220,7 +220,7 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, const AuthorizationSet &keyParams, - const std::string& ciphertext, std::string* message) { + const std::string& ciphertext, KeyBuffer* message) { auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES); auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES); auto opParams = AuthorizationSetBuilder() @@ -305,7 +305,7 @@ static void logOpensslError() { } static bool encryptWithoutKeymaster(const std::string& preKey, - const std::string& plaintext, std::string* ciphertext) { + const KeyBuffer& plaintext, std::string* ciphertext) { auto key = hashWithPrefix(kHashPrefix_keygen, preKey); key.resize(AES_KEY_BYTES); if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false; @@ -351,7 +351,7 @@ static bool encryptWithoutKeymaster(const std::string& preKey, } static bool decryptWithoutKeymaster(const std::string& preKey, - const std::string& ciphertext, std::string* plaintext) { + const std::string& ciphertext, KeyBuffer* plaintext) { if (ciphertext.size() < GCM_NONCE_BYTES + GCM_MAC_BYTES) { LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size(); return false; @@ -370,7 +370,7 @@ static bool decryptWithoutKeymaster(const std::string& preKey, logOpensslError(); return false; } - plaintext->resize(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES); + *plaintext = KeyBuffer(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES); int outlen; if (1 != EVP_DecryptUpdate(ctx.get(), reinterpret_cast(&(*plaintext)[0]), &outlen, @@ -404,7 +404,7 @@ bool pathExists(const std::string& path) { return access(path.c_str(), F_OK) == 0; } -bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) { +bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key) { if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) { PLOG(ERROR) << "key mkdir " << dir; return false; @@ -442,7 +442,7 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std:: } bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path, - const KeyAuthentication& auth, const std::string& key) { + const KeyAuthentication& auth, const KeyBuffer& key) { if (pathExists(key_path)) { LOG(ERROR) << "Already exists, cannot create key at: " << key_path; return false; @@ -460,7 +460,7 @@ bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path return true; } -bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) { +bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key) { std::string version; if (!readFileToString(dir + "/" + kFn_version, &version)) return false; if (version != kCurrentVersion) { diff --git a/KeyStorage.h b/KeyStorage.h index 63345f4..655cd17 100644 --- a/KeyStorage.h +++ b/KeyStorage.h @@ -17,6 +17,8 @@ #ifndef ANDROID_VOLD_KEYSTORAGE_H #define ANDROID_VOLD_KEYSTORAGE_H +#include "KeyBuffer.h" + #include namespace android { @@ -46,17 +48,17 @@ bool pathExists(const std::string& path); // in such a way that it can only be retrieved via Keymaster and // can be securely deleted. // It's safe to move/rename the directory after creation. -bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key); +bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key); // Create a directory at the named path, and store "key" in it as storeKey // This version creates the key in "tmp_path" then atomically renames "tmp_path" // to "key_path" thereby ensuring that the key is either stored entirely or // not at all. bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path, - const KeyAuthentication& auth, const std::string& key); + const KeyAuthentication& auth, const KeyBuffer& key); // Retrieve the key from the named directory. -bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key); +bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key); // Securely destroy the key stored in the named directory and delete the directory. bool destroyKey(const std::string& dir); diff --git a/KeyUtil.cpp b/KeyUtil.cpp index a75dfbb..7bbbf01 100644 --- a/KeyUtil.cpp +++ b/KeyUtil.cpp @@ -32,8 +32,23 @@ namespace android { namespace vold { -bool randomKey(std::string* key) { - if (ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) { +// ext4enc:TODO get this const from somewhere good +const int EXT4_KEY_DESCRIPTOR_SIZE = 8; + +// ext4enc:TODO Include structure from somewhere sensible +// MUST be in sync with ext4_crypto.c in kernel +constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1; +constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64; +constexpr int EXT4_MAX_KEY_SIZE = 64; +struct ext4_encryption_key { + uint32_t mode; + char raw[EXT4_MAX_KEY_SIZE]; + uint32_t size; +}; + +bool randomKey(KeyBuffer* key) { + *key = KeyBuffer(EXT4_AES_256_XTS_KEY_SIZE); + if (ReadRandomBytes(key->size(), key->data()) != 0) { // TODO status_t plays badly with PLOG, fix it. LOG(ERROR) << "Random read failed"; return false; @@ -60,7 +75,7 @@ static std::string generateKeyRef(const char* key, int length) { return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE); } -static bool fillKey(const std::string& key, ext4_encryption_key* ext4_key) { +static bool fillKey(const KeyBuffer& key, ext4_encryption_key* ext4_key) { if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) { LOG(ERROR) << "Wrong size key " << key.size(); return false; @@ -101,8 +116,11 @@ static bool e4cryptKeyring(key_serial_t* device_keyring) { // Install password into global keyring // Return raw key reference for use in policy -bool installKey(const std::string& key, std::string* raw_ref) { - ext4_encryption_key ext4_key; +bool installKey(const KeyBuffer& key, std::string* raw_ref) { + // Place ext4_encryption_key into automatically zeroing buffer. + KeyBuffer ext4KeyBuffer(sizeof(ext4_encryption_key)); + ext4_encryption_key &ext4_key = *reinterpret_cast(ext4KeyBuffer.data()); + if (!fillKey(key, &ext4_key)) return false; *raw_ref = generateKeyRef(ext4_key.raw, ext4_key.size); key_serial_t device_keyring; @@ -145,7 +163,7 @@ bool evictKey(const std::string& raw_ref) { bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path, std::string* key_ref) { - std::string key; + KeyBuffer key; if (pathExists(key_path)) { LOG(DEBUG) << "Key exists, using: " << key_path; if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false; @@ -168,7 +186,7 @@ bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path, } bool retrieveKey(bool create_if_absent, const std::string& key_path, - const std::string& tmp_path, std::string* key) { + const std::string& tmp_path, KeyBuffer* key) { if (pathExists(key_path)) { LOG(DEBUG) << "Key exists, using: " << key_path; if (!retrieveKey(key_path, kEmptyAuthentication, key)) return false; diff --git a/KeyUtil.h b/KeyUtil.h index d4c97b9..412b0ae 100644 --- a/KeyUtil.h +++ b/KeyUtil.h @@ -17,32 +17,21 @@ #ifndef ANDROID_VOLD_KEYUTIL_H #define ANDROID_VOLD_KEYUTIL_H +#include "KeyBuffer.h" + #include +#include namespace android { namespace vold { -// ext4enc:TODO get this const from somewhere good -const int EXT4_KEY_DESCRIPTOR_SIZE = 8; - -// ext4enc:TODO Include structure from somewhere sensible -// MUST be in sync with ext4_crypto.c in kernel -constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1; -constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64; -constexpr int EXT4_MAX_KEY_SIZE = 64; -struct ext4_encryption_key { - uint32_t mode; - char raw[EXT4_MAX_KEY_SIZE]; - uint32_t size; -}; - -bool randomKey(std::string* key); -bool installKey(const std::string& key, std::string* raw_ref); +bool randomKey(KeyBuffer* key); +bool installKey(const KeyBuffer& key, std::string* raw_ref); bool evictKey(const std::string& raw_ref); bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path, std::string* key_ref); bool retrieveKey(bool create_if_absent, const std::string& key_path, - const std::string& tmp_path, std::string* key); + const std::string& tmp_path, KeyBuffer* key); } // namespace vold } // namespace android diff --git a/Keymaster.cpp b/Keymaster.cpp index ffa3a7a..1bbeb61 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -31,25 +31,23 @@ KeymasterOperation::~KeymasterOperation() { if (mDevice.get()) mDevice->abort(mOpHandle); } -bool KeymasterOperation::updateCompletely(const std::string& input, std::string* output) { - if (output) - output->clear(); - auto it = input.begin(); - uint32_t inputConsumed; +bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, + const std::function consumer) { + uint32_t inputConsumed = 0; ErrorCode km_error; - auto hidlCB = [&] (ErrorCode ret, uint32_t _inputConsumed, + auto hidlCB = [&] (ErrorCode ret, uint32_t inputConsumedDelta, const hidl_vec& /*ignored*/, const hidl_vec& _output) { km_error = ret; if (km_error != ErrorCode::OK) return; - inputConsumed = _inputConsumed; - if (output) - output->append(reinterpret_cast(&_output[0]), _output.size()); + inputConsumed += inputConsumedDelta; + consumer(reinterpret_cast(&_output[0]), _output.size()); }; - while (it != input.end()) { - size_t toRead = static_cast(input.end() - it); - auto inputBlob = blob2hidlVec(reinterpret_cast(&*it), toRead); + while (inputConsumed != inputLen) { + size_t toRead = static_cast(inputLen - inputConsumed); + auto inputBlob = + blob2hidlVec(reinterpret_cast(&input[inputConsumed]), toRead); auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, hidlCB); if (!error.isOk()) { LOG(ERROR) << "update failed: " << error.description(); @@ -61,12 +59,11 @@ bool KeymasterOperation::updateCompletely(const std::string& input, std::string* mDevice = nullptr; return false; } - if (inputConsumed > toRead) { + if (inputConsumed > inputLen) { LOG(ERROR) << "update reported too much input consumed"; mDevice = nullptr; return false; } - it += inputConsumed; } return true; } diff --git a/Keymaster.h b/Keymaster.h index 4bc0df7..dc6f1bc 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -19,6 +19,8 @@ #ifdef __cplusplus +#include "KeyBuffer.h" + #include #include #include @@ -51,7 +53,14 @@ class KeymasterOperation { ErrorCode errorCode() { return mError; } // Call "update" repeatedly until all of the input is consumed, and // concatenate the output. Return true on success. - bool updateCompletely(const std::string& input, std::string* output); + template + bool updateCompletely(TI& input, TO* output) { + if (output) output->clear(); + return updateCompletely(input.data(), input.size(), [&](const char* b, size_t n) { + if (output) std::copy(b, b+n, std::back_inserter(*output)); + }); + } + // Finish and write the output to this string, unless pointer is null. bool finish(std::string* output); // Move constructor @@ -80,6 +89,10 @@ class KeymasterOperation { KeymasterOperation(ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError {error} {} + + bool updateCompletely(const char* input, size_t inputLen, + const std::function consumer); + sp mDevice; uint64_t mOpHandle; ErrorCode mError; diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 743e08c..8311813 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -14,11 +14,13 @@ * limitations under the License. */ +#include "KeyBuffer.h" #include "MetadataCrypt.h" #include #include #include +#include #include #include @@ -45,6 +47,8 @@ extern struct fstab *fstab; #define TABLE_LOAD_RETRIES 10 #define DEFAULT_KEY_TARGET_TYPE "default-key" +using android::vold::KeyBuffer; + static const std::string kDmNameUserdata = "userdata"; static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { @@ -68,7 +72,7 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { return true; } -static bool read_key(bool create_if_absent, std::string* key) { +static bool read_key(bool create_if_absent, KeyBuffer* key) { auto data_rec = fs_mgr_get_crypt_entry(fstab); if (!data_rec) { LOG(ERROR) << "Failed to get data_rec"; @@ -93,14 +97,14 @@ static bool read_key(bool create_if_absent, std::string* key) { return true; } -static std::string default_key_params(const std::string& real_blkdev, const std::string& key) { - std::string hex_key; +static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) { + KeyBuffer hex_key; if (android::vold::StrToHex(key, hex_key) != android::OK) { LOG(ERROR) << "Failed to turn key to hex"; - return ""; + return KeyBuffer(); } - auto res = std::string() + "AES-256-XTS " + hex_key + " " + real_blkdev + " 0"; - LOG(DEBUG) << "crypt_params: " << res; + auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0"; + LOG(DEBUG) << "crypt_params: " << std::string(res.data(), res.size()); return res; } @@ -142,7 +146,7 @@ static struct dm_ioctl* dm_ioctl_init(char *buffer, size_t buffer_size, } static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec, - const std::string& target_type, const std::string& crypt_params, + const std::string& target_type, const KeyBuffer& crypt_params, std::string* crypto_blkdev) { android::base::unique_fd dm_fd(TEMP_FAILURE_RETRY(open( "/dev/device-mapper", O_RDWR | O_CLOEXEC, 0))); @@ -167,9 +171,9 @@ static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec, (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00)); io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); - unsigned long paramix = io->data_start + sizeof(struct dm_target_spec); - unsigned long nullix = paramix + crypt_params.size(); - unsigned long endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary + size_t paramix = io->data_start + sizeof(struct dm_target_spec); + size_t nullix = paramix + crypt_params.size(); + size_t endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary if (endix > sizeof(buffer)) { LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE"; @@ -182,7 +186,8 @@ static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec, tgt->sector_start = 0; tgt->length = nr_sec; target_type.copy(tgt->target_type, sizeof(tgt->target_type)); - crypt_params.copy(buffer + paramix, sizeof(buffer) - paramix); + memcpy(buffer + paramix, crypt_params.data(), + std::min(crypt_params.size(), sizeof(buffer) - paramix)); buffer[nullix] = '\0'; tgt->next = endix; @@ -246,7 +251,7 @@ static void async_kick_off() { bool e4crypt_mount_metadata_encrypted() { LOG(DEBUG) << "e4crypt_mount_default_encrypted"; - std::string key; + KeyBuffer key; if (!read_key(false, &key)) return false; auto data_rec = fs_mgr_get_crypt_entry(fstab); if (!data_rec) { @@ -275,7 +280,7 @@ bool e4crypt_enable_crypto() { return false; } - std::string key_ref; + KeyBuffer key_ref; if (!read_key(true, &key_ref)) return false; auto data_rec = fs_mgr_get_crypt_entry(fstab); diff --git a/Utils.cpp b/Utils.cpp index 395a890..b6c7bf8 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -351,18 +351,20 @@ pid_t ForkExecvpAsync(const std::vector& args) { } status_t ReadRandomBytes(size_t bytes, std::string& out) { - out.clear(); + out.resize(bytes); + return ReadRandomBytes(bytes, &out[0]); +} +status_t ReadRandomBytes(size_t bytes, char* buf) { 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); + while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], bytes))) > 0) { bytes -= n; + buf += n; } close(fd); @@ -434,6 +436,15 @@ status_t StrToHex(const std::string& str, std::string& hex) { return OK; } +status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex) { + hex.clear(); + for (size_t i = 0; i < str.size(); i++) { + hex.push_back(kLookup[(str.data()[i] & 0xF0) >> 4]); + hex.push_back(kLookup[str.data()[i] & 0x0F]); + } + return OK; +} + status_t NormalizeHex(const std::string& in, std::string& out) { std::string tmp; if (HexToStr(in, tmp)) { diff --git a/Utils.h b/Utils.h index 7272fe1..82ac440 100644 --- a/Utils.h +++ b/Utils.h @@ -17,6 +17,8 @@ #ifndef ANDROID_VOLD_UTILS_H #define ANDROID_VOLD_UTILS_H +#include "KeyBuffer.h" + #include #include #include @@ -78,12 +80,15 @@ status_t ForkExecvp(const std::vector& args, pid_t ForkExecvpAsync(const std::vector& args); status_t ReadRandomBytes(size_t bytes, std::string& out); +status_t ReadRandomBytes(size_t bytes, char* buffer); status_t GenerateRandomUuid(std::string& out); /* Converts hex string to raw bytes, ignoring [ :-] */ status_t HexToStr(const std::string& hex, std::string& str); /* Converts raw bytes to hex string */ status_t StrToHex(const std::string& str, std::string& hex); +/* Converts raw key bytes to hex string */ +status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex); /* Normalize given hex string into consistent format */ status_t NormalizeHex(const std::string& in, std::string& out);