Skip to content

Commit

Permalink
Generalize CryptoType infrastructure
Browse files Browse the repository at this point in the history
More consistency between MetadataCrypt and cryptfs, and steps towards
supporting Adiantum properly in MetadataCrypt.

Test: create private volume on Cuttlefish
Bug: 147814592
Change-Id: Ic3993c1fde11b4f5a9e6cc8ee588a7d92241c6ab
  • Loading branch information
ciphergoth committed Feb 14, 2020
1 parent a661fb6 commit 220567c
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 145 deletions.
3 changes: 2 additions & 1 deletion Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ cc_library_static {
"Benchmark.cpp",
"CheckEncryption.cpp",
"Checkpoint.cpp",
"CryptoType.cpp",
"Devmapper.cpp",
"EncryptInplace.cpp",
"FileDeviceUtils.cpp",
Expand Down Expand Up @@ -141,8 +142,8 @@ cc_library_static {
"model/ObbVolume.cpp",
"model/PrivateVolume.cpp",
"model/PublicVolume.cpp",
"model/VolumeBase.cpp",
"model/StubVolume.cpp",
"model/VolumeBase.cpp",
],
product_variables: {
arc: {
Expand Down
43 changes: 43 additions & 0 deletions CryptoType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2020 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 "CryptoType.h"

#include <string.h>

#include <android-base/logging.h>
#include <cutils/properties.h>

namespace android {
namespace vold {

const CryptoType& lookup_crypto_algorithm(const CryptoType table[], int table_len,
const CryptoType& default_alg, const char* property) {
char paramstr[PROPERTY_VALUE_MAX];

property_get(property, paramstr, default_alg.get_config_name());
for (int i = 0; i < table_len; i++) {
if (strcmp(paramstr, table[i].get_config_name()) == 0) {
return table[i];
}
}
LOG(ERROR) << "Invalid name (" << paramstr << ") for " << property << ". Defaulting to "
<< default_alg.get_config_name() << ".";
return default_alg;
}

} // namespace vold
} // namespace android
103 changes: 103 additions & 0 deletions CryptoType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2020 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.
*/

#pragma once

#include <stdlib.h>

namespace android {
namespace vold {

// Struct representing an encryption algorithm supported by vold.
// "config_name" represents the name we give the algorithm in
// read-only properties and fstab files
// "kernel_name" is the name we present to the Linux kernel
// "keysize" is the size of the key in bytes.
struct CryptoType {
// We should only be constructing CryptoTypes as part of
// supported_crypto_types[]. We do it via this pseudo-builder pattern,
// which isn't pure or fully protected as a concession to being able to
// do it all at compile time. Add new CryptoTypes in
// supported_crypto_types[] below.
constexpr CryptoType() : CryptoType(nullptr, nullptr, 0xFFFFFFFF) {}
constexpr CryptoType set_keysize(size_t size) const {
return CryptoType(this->config_name, this->kernel_name, size);
}
constexpr CryptoType set_config_name(const char* property) const {
return CryptoType(property, this->kernel_name, this->keysize);
}
constexpr CryptoType set_kernel_name(const char* crypto) const {
return CryptoType(this->config_name, crypto, this->keysize);
}

constexpr const char* get_config_name() const { return config_name; }
constexpr const char* get_kernel_name() const { return kernel_name; }
constexpr size_t get_keysize() const { return keysize; }

private:
const char* config_name;
const char* kernel_name;
size_t keysize;

constexpr CryptoType(const char* property, const char* crypto, size_t ksize)
: config_name(property), kernel_name(crypto), keysize(ksize) {}
};

// Use the named android property to look up a type from the table
// If the property is not set or matches no table entry, return the default.
const CryptoType& lookup_crypto_algorithm(const CryptoType table[], int table_len,
const CryptoType& default_alg, const char* property);

// Some useful types

constexpr CryptoType invalid_crypto_type = CryptoType();

constexpr CryptoType aes_256_xts = CryptoType()
.set_config_name("aes-256-xts")
.set_kernel_name("aes-xts-plain64")
.set_keysize(64);

constexpr CryptoType adiantum = CryptoType()
.set_config_name("adiantum")
.set_kernel_name("xchacha12,aes-adiantum-plain64")
.set_keysize(32);

// Support compile-time validation of a crypto type table

template <typename T, size_t N>
constexpr size_t array_length(T (&)[N]) {
return N;
}

constexpr bool isValidCryptoType(size_t max_keylen, const CryptoType& crypto_type) {
return ((crypto_type.get_config_name() != nullptr) &&
(crypto_type.get_kernel_name() != nullptr) &&
(crypto_type.get_keysize() <= max_keylen));
}

// Confirms that all supported_crypto_types have a small enough keysize and
// had both set_config_name() and set_kernel_name() called.
// Note in C++11 that constexpr functions can only have a single line.
// So our code is a bit convoluted (using recursion instead of a loop),
// but it's asserting at compile time that all of our key lengths are valid.
constexpr bool validateSupportedCryptoTypes(size_t max_keylen, const CryptoType types[],
size_t len) {
return len == 0 || (isValidCryptoType(max_keylen, types[len - 1]) &&
validateSupportedCryptoTypes(max_keylen, types, len - 1));
}

} // namespace vold
} // namespace android
65 changes: 45 additions & 20 deletions MetadataCrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <libdm/dm.h>

#include "Checkpoint.h"
#include "CryptoType.h"
#include "EncryptInplace.h"
#include "KeyStorage.h"
#include "KeyUtil.h"
Expand All @@ -45,6 +46,9 @@

#define TABLE_LOAD_RETRIES 10

namespace android {
namespace vold {

using android::fs_mgr::FstabEntry;
using android::fs_mgr::GetEntryForMountPoint;
using android::vold::KeyBuffer;
Expand All @@ -55,6 +59,21 @@ static const std::string kDmNameUserdata = "userdata";
static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";

constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum};

static_assert(validateSupportedCryptoTypes(64, supported_crypto_types,
array_length(supported_crypto_types)),
"We have a CryptoType which was incompletely constructed.");

constexpr CryptoType legacy_aes_256_xts =
CryptoType().set_config_name("aes-256-xts").set_kernel_name("AES-256-XTS").set_keysize(64);

constexpr CryptoType legacy_crypto_types[] = {legacy_aes_256_xts};

static_assert(validateSupportedCryptoTypes(64, legacy_crypto_types,
array_length(legacy_crypto_types)),
"We have a CryptoType which was incompletely constructed.");

static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
// We're about to mount data not verified by verified boot. Tell Keymaster that early boot has
// ended.
Expand Down Expand Up @@ -85,9 +104,6 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
return true;
}

namespace android {
namespace vold {

// Note: It is possible to orphan a key if it is removed before deleting
// Update this once keymaster APIs change, and we have a proper commit.
static void commit_key(const std::string& dir) {
Expand Down Expand Up @@ -165,9 +181,6 @@ static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffe
return true;
}

} // namespace vold
} // namespace android

static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_sec) {
if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) {
PLOG(ERROR) << "Unable to measure size of " << real_blkdev;
Expand All @@ -176,20 +189,25 @@ static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_s
return true;
}

static std::string lookup_cipher(const std::string& cipher_name, bool is_legacy) {
if (is_legacy) {
if (cipher_name.empty() || cipher_name == "aes-256-xts") {
return "AES-256-XTS";
static const CryptoType& lookup_cipher_in_table(const CryptoType table[], int table_len,
const std::string& cipher_name) {
if (cipher_name.empty()) return table[0];
for (int i = 0; i < table_len; i++) {
if (cipher_name == table[i].get_config_name()) {
return table[i];
}
}
return invalid_crypto_type;
}

static const CryptoType& lookup_cipher(const std::string& cipher_name, bool is_legacy) {
if (is_legacy) {
return lookup_cipher_in_table(legacy_crypto_types, array_length(legacy_crypto_types),
cipher_name);
} else {
if (cipher_name.empty() || cipher_name == "aes-256-xts") {
return "aes-xts-plain64";
} else if (cipher_name == "adiantum") {
return "xchacha12,aes-adiantum-plain64";
}
return lookup_cipher_in_table(supported_crypto_types, array_length(supported_crypto_types),
cipher_name);
}
LOG(ERROR) << "No metadata cipher named " << cipher_name << " found, is_legacy=" << is_legacy;
return "";
}

static bool create_crypto_blk_dev(const std::string& dm_name, const FstabEntry* data_rec,
Expand All @@ -201,7 +219,11 @@ static bool create_crypto_blk_dev(const std::string& dm_name, const FstabEntry*
if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false;

auto cipher = lookup_cipher(data_rec->metadata_cipher, is_legacy);
if (cipher.empty()) return false;
if (cipher.get_kernel_name() == nullptr) {
LOG(ERROR) << "No metadata cipher named " << data_rec->metadata_cipher
<< " found, is_legacy=" << is_legacy;
return false;
}

KeyBuffer hex_key_buffer;
if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
Expand All @@ -218,8 +240,8 @@ static bool create_crypto_blk_dev(const std::string& dm_name, const FstabEntry*
}

DmTable table;
table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher, hex_key, data_rec->blk_device, 0,
is_legacy, set_dun);
table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher.get_kernel_name(), hex_key,
data_rec->blk_device, 0, is_legacy, set_dun);

auto& dm = DeviceMapper::Instance();
for (int i = 0;; i++) {
Expand Down Expand Up @@ -289,3 +311,6 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::
mount_via_fs_mgr(data_rec->mount_point.c_str(), crypto_blkdev.c_str());
return true;
}

} // namespace vold
} // namespace android
5 changes: 5 additions & 0 deletions MetadataCrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@

#include <string>

namespace android {
namespace vold {

bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
const std::string& mount_point, bool needs_encrypt);

} // namespace vold
} // namespace android
#endif
Loading

0 comments on commit 220567c

Please sign in to comment.