summaryrefslogtreecommitdiff
path: root/libfscrypt
diff options
context:
space:
mode:
authorPaul Crowley <paulcrowley@google.com>2019-10-24 14:51:44 -0700
committerPaul Crowley <paulcrowley@google.com>2019-10-24 20:45:40 -0700
commitf6ca2c34097e997bf0c1201f808153538368b8ea (patch)
tree8e7e2a4d43ce7678f4e564892c776e1f4bfb51d5 /libfscrypt
parentb0afbc964fc5647b7ae76a8b5179966051f939bb (diff)
downloadextras-f6ca2c34097e997bf0c1201f808153538368b8ea.tar.gz
Provide struct-based C++ interface
Replace many-parameter C interface with a cleaner and more complete C++ interface for passing around policies in a struct. Bug: 143307095 Test: treehugger Change-Id: I95aeaae211f7ad698854bcc66c6d25a0bcb24cfe
Diffstat (limited to 'libfscrypt')
l---------libfscrypt/.clang-format1
-rw-r--r--libfscrypt/fscrypt.cpp213
-rw-r--r--libfscrypt/include/fscrypt/fscrypt.h44
3 files changed, 178 insertions, 80 deletions
diff --git a/libfscrypt/.clang-format b/libfscrypt/.clang-format
new file mode 120000
index 00000000..973b2fab
--- /dev/null
+++ b/libfscrypt/.clang-format
@@ -0,0 +1 @@
+../../../build/soong/scripts/system-clang-format \ No newline at end of file
diff --git a/libfscrypt/fscrypt.cpp b/libfscrypt/fscrypt.cpp
index 66a43200..c29354f3 100644
--- a/libfscrypt/fscrypt.cpp
+++ b/libfscrypt/fscrypt.cpp
@@ -18,6 +18,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <asm/ioctl.h>
#include <cutils/properties.h>
@@ -32,6 +33,10 @@
#include <utils/misc.h>
#include <array>
+#include <string>
+#include <vector>
+
+using namespace std::string_literals;
// TODO: switch to <linux/fscrypt.h> once it's in Bionic
#ifndef FSCRYPT_POLICY_V1
@@ -69,12 +74,55 @@ struct fscrypt_policy_v2 {
#define MAX_KEY_REF_SIZE_HEX (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + 1)
+struct ModeLookupEntry {
+ std::string name;
+ int id;
+};
+
+static const auto contents_modes = std::vector<ModeLookupEntry>{
+ {"aes-256-xts"s, FS_ENCRYPTION_MODE_AES_256_XTS},
+ {"software"s, FS_ENCRYPTION_MODE_AES_256_XTS},
+ {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
+ {"ice"s, FS_ENCRYPTION_MODE_PRIVATE},
+};
+
+static const auto filenames_modes = std::vector<ModeLookupEntry>{
+ {"aes-256-cts"s, FS_ENCRYPTION_MODE_AES_256_CTS},
+ {"aes-256-heh"s, FS_ENCRYPTION_MODE_AES_256_HEH},
+ {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
+};
+
+static bool LookupModeByName(const std::vector<struct ModeLookupEntry>& modes,
+ const std::string& name, int* result) {
+ for (const auto& e : modes) {
+ if (e.name == name) {
+ *result = e.id;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool LookupModeById(const std::vector<struct ModeLookupEntry>& modes, int id,
+ std::string* result) {
+ for (const auto& e : modes) {
+ if (e.id == id) {
+ *result = e.name;
+ return true;
+ }
+ }
+ return false;
+}
+
bool fscrypt_is_native() {
char value[PROPERTY_VALUE_MAX];
property_get("ro.crypto.type", value, "none");
return !strcmp(value, "file");
}
+namespace android {
+namespace fscrypt {
+
static void log_ls(const char* dirname) {
std::array<const char*, 3> argv = {"ls", "-laZ", dirname};
int status = 0;
@@ -96,16 +144,15 @@ static void log_ls(const char* dirname) {
}
}
-static void keyrefstring(const char* key_raw_ref, size_t key_raw_ref_length, char* hex) {
- size_t j = 0;
- for (size_t i = 0; i < key_raw_ref_length; i++) {
- hex[j++] = HEX_LOOKUP[(key_raw_ref[i] & 0xF0) >> 4];
- hex[j++] = HEX_LOOKUP[key_raw_ref[i] & 0x0F];
+void BytesToHex(const std::string& bytes, std::string* hex) {
+ hex->clear();
+ for (char c : bytes) {
+ *hex += HEX_LOOKUP[(c & 0xF0) >> 4];
+ *hex += HEX_LOOKUP[c & 0x0F];
}
- hex[j] = '\0';
}
-static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode, int policy_version) {
+static uint8_t fscrypt_get_policy_flags(const EncryptionOptions& options) {
uint8_t flags = 0;
// In the original setting of v1 policies and AES-256-CTS we used 4-byte
@@ -114,7 +161,7 @@ static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode, int polic
// For everything else, use 16-byte padding. This is more secure (it helps
// hide the length of filenames), and it makes the inputs evenly divisible
// into cipher blocks which is more efficient for encryption and decryption.
- if (policy_version == 1 && filenames_encryption_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
+ if (options.version == 1 && options.filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
flags |= FS_POLICY_FLAGS_PAD_4;
} else {
flags |= FS_POLICY_FLAGS_PAD_16;
@@ -123,7 +170,7 @@ static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode, int polic
// Use DIRECT_KEY for Adiantum, since it's much more efficient but just as
// secure since Android doesn't reuse the same master key for multiple
// encryption modes.
- if (filenames_encryption_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
+ if (options.filenames_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
flags |= FS_POLICY_FLAG_DIRECT_KEY;
}
@@ -139,80 +186,105 @@ static bool fscrypt_is_encrypted(int fd) {
return ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0 || errno == EINVAL;
}
-int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t key_raw_ref_length,
- const char* contents_encryption_mode,
- const char* filenames_encryption_mode, int policy_version) {
- int contents_mode = 0;
- int filenames_mode = 0;
-
- if (!strcmp(contents_encryption_mode, "software") ||
- !strcmp(contents_encryption_mode, "aes-256-xts")) {
- contents_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
- } else if (!strcmp(contents_encryption_mode, "adiantum")) {
- contents_mode = FS_ENCRYPTION_MODE_ADIANTUM;
- } else if (!strcmp(contents_encryption_mode, "ice")) {
- contents_mode = FS_ENCRYPTION_MODE_PRIVATE;
- } else {
- LOG(ERROR) << "Invalid file contents encryption mode: "
- << contents_encryption_mode;
- return -1;
+bool OptionsToString(const EncryptionOptions& options, std::string* options_string) {
+ std::string contents_mode, filenames_mode;
+ if (!LookupModeById(contents_modes, options.contents_mode, &contents_mode)) {
+ return false;
}
+ if (!LookupModeById(filenames_modes, options.filenames_mode, &filenames_mode)) {
+ return false;
+ }
+ *options_string = contents_mode + ":" + filenames_mode + ":v" + std::to_string(options.version);
+ return true;
+}
+
+bool ParseOptions(const std::string& options_string, EncryptionOptions* options) {
+ auto parts = android::base::Split(options_string, ":");
+
+ if (parts.size() != 3) return false;
+
+ return ParseOptionsParts(parts[0], parts[1], parts[2], options);
+}
- if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
- filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
- } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
- filenames_mode = FS_ENCRYPTION_MODE_AES_256_HEH;
- } else if (!strcmp(filenames_encryption_mode, "adiantum")) {
- filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
+bool ParseOptionsParts(const std::string& contents_mode, const std::string& filenames_mode,
+ const std::string& flags, EncryptionOptions* options) {
+ int policy_version;
+ if (flags == "v1") {
+ policy_version = 1;
+ } else if (flags == "v2") {
+ policy_version = 2;
} else {
- LOG(ERROR) << "Invalid file names encryption mode: "
- << filenames_encryption_mode;
- return -1;
+ LOG(ERROR) << "Unknown flag: " << flags;
+ return false;
+ }
+ return ParseOptionsParts(contents_mode, filenames_mode, policy_version, options);
+}
+
+bool ParseOptionsParts(const std::string& contents_mode, const std::string& filenames_mode,
+ int policy_version, EncryptionOptions* options) {
+ if (!LookupModeByName(contents_modes, contents_mode, &options->contents_mode)) {
+ LOG(ERROR) << "Invalid file contents encryption mode: " << contents_mode;
+ return false;
+ }
+ if (!LookupModeByName(filenames_modes, filenames_mode, &options->filenames_mode)) {
+ LOG(ERROR) << "Invalid file names encryption mode: " << filenames_mode;
+ return false;
}
+ options->version = policy_version;
+ return true;
+}
+
+bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory) {
union {
fscrypt_policy_v1 v1;
fscrypt_policy_v2 v2;
- } policy;
- memset(&policy, 0, sizeof(policy));
+ } kern_policy;
+ memset(&kern_policy, 0, sizeof(kern_policy));
- switch (policy_version) {
+ switch (policy.options.version) {
case 1:
- if (key_raw_ref_length != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
- LOG(ERROR) << "Invalid key ref length for v1 policy: " << key_raw_ref_length;
- return -1;
+ if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Invalid key descriptor length for v1 policy: "
+ << policy.key_raw_ref.size();
+ return false;
}
// Careful: FSCRYPT_POLICY_V1 is actually 0 in the API, so make sure
// to use it here instead of a literal 1.
- policy.v1.version = FSCRYPT_POLICY_V1;
- policy.v1.contents_encryption_mode = contents_mode;
- policy.v1.filenames_encryption_mode = filenames_mode;
- policy.v1.flags = fscrypt_get_policy_flags(filenames_mode, policy_version);
- memcpy(policy.v1.master_key_descriptor, key_raw_ref, FSCRYPT_KEY_DESCRIPTOR_SIZE);
+ kern_policy.v1.version = FSCRYPT_POLICY_V1;
+ kern_policy.v1.contents_encryption_mode = policy.options.contents_mode;
+ kern_policy.v1.filenames_encryption_mode = policy.options.filenames_mode;
+ kern_policy.v1.flags = fscrypt_get_policy_flags(policy.options);
+ policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v1.master_key_descriptor),
+ FSCRYPT_KEY_DESCRIPTOR_SIZE);
break;
case 2:
- if (key_raw_ref_length != FSCRYPT_KEY_IDENTIFIER_SIZE) {
- LOG(ERROR) << "Invalid key ref length for v2 policy: " << key_raw_ref_length;
- return -1;
+ if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
+ LOG(ERROR) << "Invalid key identifier length for v2 policy: "
+ << policy.key_raw_ref.size();
+ return false;
}
- policy.v2.version = FSCRYPT_POLICY_V2;
- policy.v2.contents_encryption_mode = contents_mode;
- policy.v2.filenames_encryption_mode = filenames_mode;
- policy.v2.flags = fscrypt_get_policy_flags(filenames_mode, policy_version);
- memcpy(policy.v2.master_key_identifier, key_raw_ref, FSCRYPT_KEY_IDENTIFIER_SIZE);
+ kern_policy.v2.version = FSCRYPT_POLICY_V2;
+ kern_policy.v2.contents_encryption_mode = policy.options.contents_mode;
+ kern_policy.v2.filenames_encryption_mode = policy.options.filenames_mode;
+ kern_policy.v2.flags = fscrypt_get_policy_flags(policy.options);
+ policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v2.master_key_identifier),
+ FSCRYPT_KEY_IDENTIFIER_SIZE);
break;
default:
- LOG(ERROR) << "Invalid encryption policy version: " << policy_version;
- return -1;
+ LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
+ return false;
}
- char ref[MAX_KEY_REF_SIZE_HEX];
- keyrefstring(key_raw_ref, key_raw_ref_length, ref);
+ std::string policy_descr;
+ BytesToHex(policy.key_raw_ref, &policy_descr);
+ policy_descr += " modes "s + std::to_string(policy.options.contents_mode) + "/" +
+ std::to_string(policy.options.filenames_mode);
- android::base::unique_fd fd(open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+ android::base::unique_fd fd(open(directory.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
if (fd == -1) {
PLOG(ERROR) << "Failed to open directory " << directory;
- return -1;
+ return false;
}
bool already_encrypted = fscrypt_is_encrypted(fd);
@@ -220,7 +292,7 @@ int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t
// FS_IOC_SET_ENCRYPTION_POLICY will set the policy if the directory is
// unencrypted; otherwise it will verify that the existing policy matches.
// Setting the policy will fail if the directory is already nonempty.
- if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) != 0) {
+ if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &kern_policy) != 0) {
std::string reason;
switch (errno) {
case EEXIST:
@@ -230,20 +302,21 @@ int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t
reason = strerror(errno);
break;
}
- LOG(ERROR) << "Failed to set encryption policy of " << directory << " to " << ref
- << " modes " << contents_mode << "/" << filenames_mode << ": " << reason;
+ LOG(ERROR) << "Failed to set encryption policy of " << directory << " to " << policy_descr
+ << ": " << reason;
if (errno == ENOTEMPTY) {
- log_ls(directory);
+ log_ls(directory.c_str());
}
- return -1;
+ return false;
}
if (already_encrypted) {
- LOG(INFO) << "Verified that " << directory << " has the encryption policy " << ref
- << " modes " << contents_mode << "/" << filenames_mode;
+ LOG(INFO) << "Verified that " << directory << " has the encryption policy " << policy_descr;
} else {
- LOG(INFO) << "Encryption policy of " << directory << " set to " << ref << " modes "
- << contents_mode << "/" << filenames_mode;
+ LOG(INFO) << "Encryption policy of " << directory << " set to " << policy_descr;
}
- return 0;
+ return true;
}
+
+} // namespace fscrypt
+} // namespace android
diff --git a/libfscrypt/include/fscrypt/fscrypt.h b/libfscrypt/include/fscrypt/fscrypt.h
index 13358bb7..29617ad5 100644
--- a/libfscrypt/include/fscrypt/fscrypt.h
+++ b/libfscrypt/include/fscrypt/fscrypt.h
@@ -17,23 +17,47 @@
#ifndef _FSCRYPT_H_
#define _FSCRYPT_H_
-#include <sys/cdefs.h>
-#include <stdbool.h>
-#include <cutils/multiuser.h>
-
-__BEGIN_DECLS
+#include <string>
bool fscrypt_is_native();
-int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t key_raw_ref_length,
- const char* contents_encryption_mode,
- const char* filenames_encryption_mode, int policy_version);
-
static const char* fscrypt_unencrypted_folder = "/unencrypted";
static const char* fscrypt_key_ref = "/unencrypted/ref";
static const char* fscrypt_key_per_boot_ref = "/unencrypted/per_boot_ref";
static const char* fscrypt_key_mode = "/unencrypted/mode";
-__END_DECLS
+namespace android {
+namespace fscrypt {
+
+struct EncryptionOptions {
+ int version;
+ int contents_mode;
+ int filenames_mode;
+
+ EncryptionOptions() : version(0) {}
+};
+
+struct EncryptionPolicy {
+ EncryptionOptions options;
+ std::string key_raw_ref;
+};
+
+void BytesToHex(const std::string& bytes, std::string* hex);
+
+bool OptionsToString(const EncryptionOptions& options, std::string* options_string);
+
+// Note that right now this parses only the output from OptionsToString, not the
+// more general format that appears in fstabs.
+bool ParseOptions(const std::string& options_string, EncryptionOptions* options);
+
+bool ParseOptionsParts(const std::string& contents_mode, const std::string& filenames_mode,
+ const std::string& flags, EncryptionOptions* options);
+
+bool ParseOptionsParts(const std::string& contents_mode, const std::string& filenames_mode,
+ int policy_version, EncryptionOptions* options);
+bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory);
+
+} // namespace fscrypt
+} // namespace android
#endif // _FSCRYPT_H_