platform_system_vold/cryptfs.cpp
Eric Biggers 0803ba0985 Remove most of FDE support
Since Android 10, new devices have been required to use FBE instead of
FDE.  Therefore, the FDE code is no longer needed.

Remove most of cryptfs.cpp.  A few parts of it need to be kept in order
to support the dm-crypt method of adoptable storage encryption.

Keep the FDE-specific binder methods stubbed out for now until their
callers can be removed.

Bug: 191796797
Change-Id: I90b1e4cacd2f3e5cce77a82a0af744fcc7da9400
2021-11-09 16:09:33 -08:00

198 lines
6.9 KiB
C++

/*
* Copyright (C) 2010 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.
*/
//
// This file contains the implementation of the dm-crypt volume metadata
// encryption method, which is deprecated. Devices that launched with Android
// 11 or higher use a different method instead. For details, see
// https://source.android.com/security/encryption/metadata#configuration-on-adoptable-storage
//
#define LOG_TAG "Cryptfs"
#include "cryptfs.h"
#include "CryptoType.h"
#include "Utils.h"
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <cutils/properties.h>
#include <libdm/dm.h>
#include <log/log.h>
#include <chrono>
using android::base::ParseUint;
using android::vold::CryptoType;
using android::vold::KeyBuffer;
using android::vold::KeyGeneration;
using namespace android::dm;
using namespace android::vold;
using namespace std::chrono_literals;
#define MAX_KEY_LEN 48
#define TABLE_LOAD_RETRIES 10
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;
}
const KeyGeneration cryptfs_get_keygen() {
return KeyGeneration{get_crypto_type().get_keysize(), true, false};
}
/* Convert a binary key of specified length into an ascii hex string equivalent,
* without the leading 0x and with null termination
*/
static void convert_key_to_hex_ascii(const KeyBuffer& key, char* key_ascii) {
unsigned int i, a;
unsigned char nibble;
for (i = 0, a = 0; i < key.size(); i++, a += 2) {
/* For each byte, write out two ascii hex digits */
nibble = (key[i] >> 4) & 0xf;
key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30);
nibble = key[i] & 0xf;
key_ascii[a + 1] = nibble + (nibble > 9 ? 0x37 : 0x30);
}
/* Add the null termination */
key_ascii[a] = '\0';
}
/*
* If the ro.crypto.fde_sector_size system property is set, append the
* parameters to make dm-crypt use the specified crypto sector size and round
* the crypto device size down to a crypto sector boundary.
*/
static int add_sector_size_param(DmTargetCrypt* target, uint64_t* nr_sec) {
constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
char value[PROPERTY_VALUE_MAX];
if (property_get(DM_CRYPT_SECTOR_SIZE, value, "") > 0) {
unsigned int sector_size;
if (!ParseUint(value, &sector_size) || sector_size < 512 || sector_size > 4096 ||
(sector_size & (sector_size - 1)) != 0) {
SLOGE("Invalid value for %s: %s. Must be >= 512, <= 4096, and a power of 2\n",
DM_CRYPT_SECTOR_SIZE, value);
return -1;
}
target->SetSectorSize(sector_size);
// With this option, IVs will match the sector numbering, instead
// of being hard-coded to being based on 512-byte sectors.
target->SetIvLargeSectors();
// Round the crypto device size down to a crypto sector boundary.
*nr_sec &= ~((sector_size / 512) - 1);
}
return 0;
}
/*
* Called by vold when it's asked to mount an encrypted external
* storage volume. The incoming partition has no crypto header/footer,
* as any metadata is been stored in a separate, small partition. We
* assume it must be using our same crypt type and keysize.
*/
int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const KeyBuffer& key,
std::string* out_crypto_blkdev) {
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;
if (android::vold::GetBlockDev512Sectors(real_blkdev, &nr_sec) != android::OK) {
SLOGE("Failed to get size of %s: %s", real_blkdev, strerror(errno));
return -1;
}
auto& dm = DeviceMapper::Instance();
// We need two ASCII characters to represent each byte, and need space for
// the '\0' terminator.
char key_ascii[MAX_KEY_LEN * 2 + 1];
convert_key_to_hex_ascii(key, key_ascii);
auto target = std::make_unique<DmTargetCrypt>(0, nr_sec, crypto_type.get_kernel_name(),
key_ascii, 0, real_blkdev, 0);
target->AllowDiscards();
if (fscrypt_is_native() &&
android::base::GetBoolProperty("ro.crypto.allow_encrypt_override", false)) {
target->AllowEncryptOverride();
}
if (add_sector_size_param(target.get(), &nr_sec)) {
SLOGE("Error processing dm-crypt sector size param\n");
return -1;
}
DmTable table;
table.AddTarget(std::move(target));
int load_count = 1;
while (load_count < TABLE_LOAD_RETRIES) {
if (dm.CreateDevice(label, table)) {
break;
}
load_count++;
}
if (load_count >= TABLE_LOAD_RETRIES) {
SLOGE("Cannot load dm-crypt mapping table.\n");
return -1;
}
if (load_count > 1) {
SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
}
if (!dm.GetDmDevicePathByName(label, out_crypto_blkdev)) {
SLOGE("Cannot determine dm-crypt path for %s.\n", label);
return -1;
}
/* Ensure the dm device has been created before returning. */
if (android::vold::WaitForFile(out_crypto_blkdev->c_str(), 1s) < 0) {
// WaitForFile generates a suitable log message
return -1;
}
return 0;
}