Zero memory used for encryuption keys. am: e2e2d308df
am: fce5bc8f14
Change-Id: I06f4be03107eca78ac98affafb9fb612d65f1a44
This commit is contained in:
commit
ea90d0504b
13 changed files with 217 additions and 75 deletions
|
@ -27,6 +27,7 @@ common_src_files := \
|
|||
MoveTask.cpp \
|
||||
Benchmark.cpp \
|
||||
TrimTask.cpp \
|
||||
KeyBuffer.cpp \
|
||||
Keymaster.cpp \
|
||||
KeyStorage.cpp \
|
||||
KeyUtil.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<userid_t> s_ephemeral_users;
|
|||
std::map<userid_t, std::string> s_de_key_raw_refs;
|
||||
std::map<userid_t, std::string> s_ce_key_raw_refs;
|
||||
// TODO abolish this map, per b/26948053
|
||||
std::map<userid_t, std::string> s_ce_keys;
|
||||
std::map<userid_t, KeyBuffer> 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;
|
||||
|
|
37
KeyBuffer.cpp
Normal file
37
KeyBuffer.cpp
Normal file
|
@ -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 <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
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
|
||||
|
63
KeyBuffer.h
Normal file
63
KeyBuffer.h
Normal file
|
@ -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 <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
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<char> {
|
||||
public:
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
memset_s(p, 0, n);
|
||||
std::allocator<char>::deallocate(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
// Char vector that zeroes memory when deallocating.
|
||||
using KeyBuffer = std::vector<char, ZeroingAllocator>;
|
||||
|
||||
// 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
|
||||
|
|
@ -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<uint8_t*>(&(*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) {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef ANDROID_VOLD_KEYSTORAGE_H
|
||||
#define ANDROID_VOLD_KEYSTORAGE_H
|
||||
|
||||
#include "KeyBuffer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
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);
|
||||
|
|
32
KeyUtil.cpp
32
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<ext4_encryption_key*>(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;
|
||||
|
|
23
KeyUtil.h
23
KeyUtil.h
|
@ -17,32 +17,21 @@
|
|||
#ifndef ANDROID_VOLD_KEYUTIL_H
|
||||
#define ANDROID_VOLD_KEYUTIL_H
|
||||
|
||||
#include "KeyBuffer.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
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
|
||||
|
|
|
@ -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<void(const char*, size_t)> 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<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) {
|
||||
km_error = ret;
|
||||
if (km_error != ErrorCode::OK) return;
|
||||
inputConsumed = _inputConsumed;
|
||||
if (output)
|
||||
output->append(reinterpret_cast<const char*>(&_output[0]), _output.size());
|
||||
inputConsumed += inputConsumedDelta;
|
||||
consumer(reinterpret_cast<const char*>(&_output[0]), _output.size());
|
||||
};
|
||||
|
||||
while (it != input.end()) {
|
||||
size_t toRead = static_cast<size_t>(input.end() - it);
|
||||
auto inputBlob = blob2hidlVec(reinterpret_cast<const uint8_t*>(&*it), toRead);
|
||||
while (inputConsumed != inputLen) {
|
||||
size_t toRead = static_cast<size_t>(inputLen - inputConsumed);
|
||||
auto inputBlob =
|
||||
blob2hidlVec(reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
|
||||
auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), 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;
|
||||
}
|
||||
|
|
15
Keymaster.h
15
Keymaster.h
|
@ -19,6 +19,8 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "KeyBuffer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -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 <class TI, class TO>
|
||||
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<void(const char*, size_t)> consumer);
|
||||
|
||||
sp<IKeymasterDevice> mDevice;
|
||||
uint64_t mOpHandle;
|
||||
ErrorCode mError;
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "KeyBuffer.h"
|
||||
#include "MetadataCrypt.h"
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
@ -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);
|
||||
|
|
19
Utils.cpp
19
Utils.cpp
|
@ -351,18 +351,20 @@ pid_t ForkExecvpAsync(const std::vector<std::string>& 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)) {
|
||||
|
|
5
Utils.h
5
Utils.h
|
@ -17,6 +17,8 @@
|
|||
#ifndef ANDROID_VOLD_UTILS_H
|
||||
#define ANDROID_VOLD_UTILS_H
|
||||
|
||||
#include "KeyBuffer.h"
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <cutils/multiuser.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
@ -78,12 +80,15 @@ status_t ForkExecvp(const std::vector<std::string>& args,
|
|||
pid_t ForkExecvpAsync(const std::vector<std::string>& 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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue