Merge changes Ic3993c1f,I06645bb4 am: ac34e9aa3e am: b62afed286 am: 54d05de798
Change-Id: Ib122e011bb7be162b76b94a31885863d2aff6d1e
diff --git a/Android.bp b/Android.bp
index 1646c42..a420078 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,6 +112,7 @@
"Benchmark.cpp",
"CheckEncryption.cpp",
"Checkpoint.cpp",
+ "CryptoType.cpp",
"Devmapper.cpp",
"EncryptInplace.cpp",
"FileDeviceUtils.cpp",
@@ -142,8 +143,8 @@
"model/ObbVolume.cpp",
"model/PrivateVolume.cpp",
"model/PublicVolume.cpp",
- "model/VolumeBase.cpp",
"model/StubVolume.cpp",
+ "model/VolumeBase.cpp",
],
product_variables: {
arc: {
diff --git a/CryptoType.cpp b/CryptoType.cpp
new file mode 100644
index 0000000..155848e
--- /dev/null
+++ b/CryptoType.cpp
@@ -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
diff --git a/CryptoType.h b/CryptoType.h
new file mode 100644
index 0000000..7ec419b
--- /dev/null
+++ b/CryptoType.h
@@ -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
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 76ea9eb..5a1a3c3 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -36,6 +36,7 @@
#include <libdm/dm.h>
#include "Checkpoint.h"
+#include "CryptoType.h"
#include "EncryptInplace.h"
#include "KeyStorage.h"
#include "KeyUtil.h"
@@ -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;
@@ -55,6 +59,21 @@
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.
@@ -85,9 +104,6 @@
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) {
@@ -165,9 +181,6 @@
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;
@@ -176,20 +189,25 @@
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";
- }
- } else {
- if (cipher_name.empty() || cipher_name == "aes-256-xts") {
- return "aes-xts-plain64";
- } else if (cipher_name == "adiantum") {
- return "xchacha12,aes-adiantum-plain64";
+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];
}
}
- LOG(ERROR) << "No metadata cipher named " << cipher_name << " found, is_legacy=" << is_legacy;
- return "";
+ 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 {
+ return lookup_cipher_in_table(supported_crypto_types, array_length(supported_crypto_types),
+ cipher_name);
+ }
}
static bool create_crypto_blk_dev(const std::string& dm_name, const FstabEntry* data_rec,
@@ -201,7 +219,11 @@
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) {
@@ -218,8 +240,8 @@
}
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++) {
@@ -289,3 +311,6 @@
mount_via_fs_mgr(data_rec->mount_point.c_str(), crypto_blkdev.c_str());
return true;
}
+
+} // namespace vold
+} // namespace android
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index cd0f5e5..a1ce7d8 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -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
diff --git a/cryptfs.cpp b/cryptfs.cpp
index def306d..530d78e 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -19,6 +19,7 @@
#include "cryptfs.h"
#include "Checkpoint.h"
+#include "CryptoType.h"
#include "EncryptInplace.h"
#include "FsCrypt.h"
#include "Keymaster.h"
@@ -74,6 +75,7 @@
using android::base::ParseUint;
using android::base::StringPrintf;
using android::fs_mgr::GetEntryForMountPoint;
+using android::vold::CryptoType;
using android::vold::KeyBuffer;
using namespace android::dm;
using namespace std::chrono_literals;
@@ -299,6 +301,28 @@
static int master_key_saved = 0;
static struct crypt_persist_data* persist_data = NULL;
+constexpr CryptoType aes_128_cbc = CryptoType()
+ .set_config_name("AES-128-CBC")
+ .set_kernel_name("aes-cbc-essiv:sha256")
+ .set_keysize(16);
+
+constexpr CryptoType supported_crypto_types[] = {aes_128_cbc, android::vold::adiantum};
+
+static_assert(validateSupportedCryptoTypes(MAX_KEY_LEN, supported_crypto_types,
+ array_length(supported_crypto_types)),
+ "We have a CryptoType with keysize > MAX_KEY_LEN or which was "
+ "incompletely constructed.");
+
+static const CryptoType& get_crypto_type() {
+ // We only want to parse this read-only property once. But we need to wait
+ // until the system is initialized before we can read it. So we use a static
+ // scoped within this function to get it only once.
+ static CryptoType crypto_type =
+ lookup_crypto_algorithm(supported_crypto_types, array_length(supported_crypto_types),
+ aes_128_cbc, "ro.crypto.fde_algorithm");
+ return crypto_type;
+}
+
/* Should we use keymaster? */
static int keymaster_check_compatibility() {
return keymaster_compatibility_cryptfs_scrypt();
@@ -429,118 +453,6 @@
return;
}
-namespace {
-
-struct CryptoType;
-
-// Use to get the CryptoType in use on this device.
-const CryptoType& get_crypto_type();
-
-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(uint32_t size) const {
- return CryptoType(this->property_name, this->crypto_name, size);
- }
- constexpr CryptoType set_property_name(const char* property) const {
- return CryptoType(property, this->crypto_name, this->keysize);
- }
- constexpr CryptoType set_crypto_name(const char* crypto) const {
- return CryptoType(this->property_name, crypto, this->keysize);
- }
-
- constexpr const char* get_property_name() const { return property_name; }
- constexpr const char* get_crypto_name() const { return crypto_name; }
- constexpr uint32_t get_keysize() const { return keysize; }
-
- private:
- const char* property_name;
- const char* crypto_name;
- uint32_t keysize;
-
- constexpr CryptoType(const char* property, const char* crypto, uint32_t ksize)
- : property_name(property), crypto_name(crypto), keysize(ksize) {}
- friend const CryptoType& get_crypto_type();
- static const CryptoType& get_device_crypto_algorithm();
-};
-
-// We only want to parse this read-only property once. But we need to wait
-// until the system is initialized before we can read it. So we use a static
-// scoped within this function to get it only once.
-const CryptoType& get_crypto_type() {
- static CryptoType crypto_type = CryptoType::get_device_crypto_algorithm();
- return crypto_type;
-}
-
-constexpr CryptoType default_crypto_type = CryptoType()
- .set_property_name("AES-128-CBC")
- .set_crypto_name("aes-cbc-essiv:sha256")
- .set_keysize(16);
-
-constexpr CryptoType supported_crypto_types[] = {
- default_crypto_type,
- CryptoType()
- .set_property_name("adiantum")
- .set_crypto_name("xchacha12,aes-adiantum-plain64")
- .set_keysize(32),
- // Add new CryptoTypes here. Order is not important.
-};
-
-// ---------- START COMPILE-TIME SANITY CHECK BLOCK -------------------------
-// We confirm all supported_crypto_types have a small enough keysize and
-// had both set_property_name() and set_crypto_name() called.
-
-template <typename T, size_t N>
-constexpr size_t array_length(T (&)[N]) {
- return N;
-}
-
-constexpr bool indexOutOfBoundsForCryptoTypes(size_t index) {
- return (index >= array_length(supported_crypto_types));
-}
-
-constexpr bool isValidCryptoType(const CryptoType& crypto_type) {
- return ((crypto_type.get_property_name() != nullptr) &&
- (crypto_type.get_crypto_name() != nullptr) &&
- (crypto_type.get_keysize() <= MAX_KEY_LEN));
-}
-
-// 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 index) {
- return indexOutOfBoundsForCryptoTypes(index) ||
- (isValidCryptoType(supported_crypto_types[index]) &&
- validateSupportedCryptoTypes(index + 1));
-}
-
-static_assert(validateSupportedCryptoTypes(0),
- "We have a CryptoType with keysize > MAX_KEY_LEN or which was "
- "incompletely constructed.");
-// ---------- END COMPILE-TIME SANITY CHECK BLOCK -------------------------
-
-// Don't call this directly, use get_crypto_type(), which caches this result.
-const CryptoType& CryptoType::get_device_crypto_algorithm() {
- constexpr char CRYPT_ALGO_PROP[] = "ro.crypto.fde_algorithm";
- char paramstr[PROPERTY_VALUE_MAX];
-
- property_get(CRYPT_ALGO_PROP, paramstr, default_crypto_type.get_property_name());
- for (auto const& ctype : supported_crypto_types) {
- if (strcmp(paramstr, ctype.get_property_name()) == 0) {
- return ctype;
- }
- }
- ALOGE("Invalid name (%s) for %s. Defaulting to %s\n", paramstr, CRYPT_ALGO_PROP,
- default_crypto_type.get_property_name());
- return default_crypto_type;
-}
-
-} // namespace
-
/**
* Gets the default device scrypt parameters for key derivation time tuning.
* The parameters should lead to about one second derivation time for the
@@ -560,14 +472,10 @@
ftr->p_factor = pf;
}
-uint32_t cryptfs_get_keysize() {
+size_t cryptfs_get_keysize() {
return get_crypto_type().get_keysize();
}
-const char* cryptfs_get_crypto_name() {
- return get_crypto_type().get_crypto_name();
-}
-
static uint64_t get_fs_size(const char* dev) {
int fd, block_size;
struct ext4_super_block sb;
@@ -1929,9 +1837,10 @@
*/
int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const KeyBuffer& key,
std::string* out_crypto_blkdev) {
- if (key.size() != cryptfs_get_keysize()) {
- SLOGE("Raw keysize %zu does not match crypt keysize %" PRIu32, key.size(),
- cryptfs_get_keysize());
+ auto crypto_type = get_crypto_type();
+ if (key.size() != crypto_type.get_keysize()) {
+ SLOGE("Raw keysize %zu does not match crypt keysize %zu", key.size(),
+ crypto_type.get_keysize());
return -1;
}
uint64_t nr_sec = 0;
@@ -1943,8 +1852,8 @@
struct crypt_mnt_ftr ext_crypt_ftr;
memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
ext_crypt_ftr.fs_size = nr_sec;
- ext_crypt_ftr.keysize = cryptfs_get_keysize();
- strlcpy((char*)ext_crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(),
+ ext_crypt_ftr.keysize = crypto_type.get_keysize();
+ strlcpy((char*)ext_crypt_ftr.crypto_type_name, crypto_type.get_kernel_name(),
MAX_CRYPTO_TYPE_NAME_LEN);
uint32_t flags = 0;
if (fscrypt_is_native() &&
@@ -2078,7 +1987,7 @@
}
/* Initialize a crypt_mnt_ftr structure. The keysize is
- * defaulted to cryptfs_get_keysize() bytes, and the filesystem size to 0.
+ * defaulted to get_crypto_type().get_keysize() bytes, and the filesystem size to 0.
* Presumably, at a minimum, the caller will update the
* filesystem size and crypto_type_name after calling this function.
*/
@@ -2090,7 +1999,7 @@
ftr->major_version = CURRENT_MAJOR_VERSION;
ftr->minor_version = CURRENT_MINOR_VERSION;
ftr->ftr_size = sizeof(struct crypt_mnt_ftr);
- ftr->keysize = cryptfs_get_keysize();
+ ftr->keysize = get_crypto_type().get_keysize();
switch (keymaster_check_compatibility()) {
case 1:
@@ -2334,7 +2243,7 @@
crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
}
crypt_ftr.crypt_type = crypt_type;
- strlcpy((char*)crypt_ftr.crypto_type_name, cryptfs_get_crypto_name(),
+ strlcpy((char*)crypt_ftr.crypto_type_name, get_crypto_type().get_kernel_name(),
MAX_CRYPTO_TYPE_NAME_LEN);
/* Make an encrypted master key */
diff --git a/cryptfs.h b/cryptfs.h
index 9b5eae7..b34a8d9 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -74,7 +74,6 @@
void cryptfs_clear_password(void);
int cryptfs_isConvertibleToFBE(void);
-uint32_t cryptfs_get_keysize();
-const char* cryptfs_get_crypto_name();
+size_t cryptfs_get_keysize();
#endif /* ANDROID_VOLD_CRYPTFS_H */