Securely encrypt the master key
Move all key management into vold
Reuse vold's existing key management through the crypto footer
to manage the device wide keys.
Use ro.crypto.type flag to determine crypto type, which prevents
any issues when running in block encrypted mode, as well as speeding
up boot in block or no encryption.
This is one of four changes to enable this functionality:
https://android-review.googlesource.com/#/c/148586/
https://android-review.googlesource.com/#/c/148604/
https://android-review.googlesource.com/#/c/148606/
https://android-review.googlesource.com/#/c/148607/
Bug: 18151196
Change-Id: I7a4ef3f3a937c45ff18f17c9ad1398293a8630f3
diff --git a/ext4_utils/ext4_crypt.cpp b/ext4_utils/ext4_crypt.cpp
index bb57332..7d3dc91 100644
--- a/ext4_utils/ext4_crypt.cpp
+++ b/ext4_utils/ext4_crypt.cpp
@@ -1,120 +1,132 @@
+/*
+ * Copyright (c) 2015 Google, Inc.
+ */
+
#define TAG "ext4_utils"
-#include "ext4_crypt.h"
+#include "ext4_crypt_init_extensions.h"
-#include <string>
-#include <fstream>
-#include <map>
-
+#include <dirent.h>
#include <errno.h>
-#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/xattr.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
#include <cutils/klog.h>
-#include <cutils/properties.h>
#include "unencrypted_properties.h"
-namespace {
- std::map<std::string, std::string> s_password_store;
+#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy"
+#define EXT4_KEYREF_DELIMITER ((char)'.')
+
+// ext4enc:TODO Include structure from somewhere sensible
+// MUST be in sync with ext4_crypto.c in kernel
+#define EXT4_MAX_KEY_SIZE 76
+struct ext4_encryption_key {
+ uint32_t mode;
+ char raw[EXT4_MAX_KEY_SIZE];
+ uint32_t size;
+};
+
+/* Validate that all path items are available and accessible. */
+static int is_path_valid(const char *path)
+{
+ if (access(path, W_OK)) {
+ KLOG_ERROR(TAG, "Can't access %s: %s\n",strerror(errno), path);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Checks whether the policy provided is valid */
+static int is_keyref_valid(const char *keyref)
+{
+ char *period = 0;
+ size_t key_location_len = 0;
+
+ /* Key ref must have a key and location delimiter character. */
+ period = strchr(keyref, EXT4_KEYREF_DELIMITER);
+ if (!period) {
+ return 0;
+ }
+
+ /* period must be >= keyref. */
+ key_location_len = period - keyref;
+
+ if (strncmp(keyref, "@t", key_location_len) == 0 ||
+ strncmp(keyref, "@p", key_location_len) == 0 ||
+ strncmp(keyref, "@s", key_location_len) == 0 ||
+ strncmp(keyref, "@u", key_location_len) == 0 ||
+ strncmp(keyref, "@g", key_location_len) == 0 ||
+ strncmp(keyref, "@us", key_location_len) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int is_dir_empty(const char *dirname)
+{
+ int n = 0;
+ struct dirent *d;
+ DIR *dir;
+
+ dir = opendir(dirname);
+ while ((d = readdir(dir)) != NULL) {
+ if (strcmp(d->d_name, "lost+found") == 0) {
+ // Skip lost+found directory
+ } else if (++n > 2) {
+ break;
+ }
+ }
+ closedir(dir);
+ return n <= 2;
+}
+
+int do_policy_set(const char *directory, const char *policy)
+{
+ struct stat st;
+ ssize_t ret;
+
+ if (!is_keyref_valid(policy)) {
+ KLOG_ERROR(TAG, "Policy has invalid format.\n");
+ return -EINVAL;
+ }
+
+ if (!is_path_valid(directory)) {
+ return -EINVAL;
+ }
+
+ stat(directory, &st);
+ if (!S_ISDIR(st.st_mode)) {
+ KLOG_ERROR(TAG, "Can only set policy on a directory (%s)\n", directory);
+ return -EINVAL;
+ }
+
+ if (!is_dir_empty(directory)) {
+ KLOG_ERROR(TAG, "Can only set policy on an empty directory (%s)\n",
+ directory);
+ return -EINVAL;
+ }
+
+ ret = lsetxattr(directory, XATTR_NAME_ENCRYPTION_POLICY, policy,
+ strlen(policy), 0);
+
+ if (ret) {
+ KLOG_ERROR(TAG, "Failed to set encryption policy for %s: %s\n",
+ directory, strerror(errno));
+ return -EINVAL;
+ }
+
+ KLOG_INFO(TAG, "Encryption policy for %s is set to %s\n", directory, policy);
+ return 0;
}
bool e4crypt_non_default_key(const char* dir)
{
- int type = e4crypt_get_password_type(dir);
-
- // ext4enc:TODO Use consts, not 1 here
- return type != -1 && type != 1;
-}
-
-int e4crypt_get_password_type(const char* path)
-{
- UnencryptedProperties props(path);
- if (props.Get<std::string>(properties::key).empty()) {
- KLOG_INFO(TAG, "No master key, so not ext4enc\n");
- return -1;
- }
-
- return props.Get<int>(properties::type, 1);
-}
-
-int e4crypt_change_password(const char* path, int crypt_type,
- const char* password)
-{
- // ext4enc:TODO Encrypt master key with password securely. Store hash of
- // master key for validation
- UnencryptedProperties props(path);
- if ( props.Set(properties::password, password)
- && props.Set(properties::type, crypt_type))
- return 0;
- return -1;
-}
-
-int e4crypt_crypto_complete(const char* path)
-{
- KLOG_INFO(TAG, "ext4 crypto complete called on %s\n", path);
- if (UnencryptedProperties(path).Get<std::string>(properties::key).empty()) {
- KLOG_INFO(TAG, "No master key, so not ext4enc\n");
- return -1;
- }
-
- return 0;
-}
-
-int e4crypt_check_passwd(const char* path, const char* password)
-{
- UnencryptedProperties props(path);
- if (props.Get<std::string>(properties::key).empty()) {
- KLOG_INFO(TAG, "No master key, so not ext4enc\n");
- return -1;
- }
-
- auto actual_password = props.Get<std::string>(properties::password);
-
- if (actual_password == password) {
- s_password_store[path] = password;
- return 0;
- } else {
- return -1;
- }
-}
-
-int e4crypt_restart(const char* path)
-{
- int rc = 0;
-
- KLOG_INFO(TAG, "ext4 restart called on %s\n", path);
- property_set("vold.decrypt", "trigger_reset_main");
- KLOG_INFO(TAG, "Just asked init to shut down class main\n");
- sleep(2);
-
- std::string tmp_path = std::string() + path + "/tmp_mnt";
-
- // ext4enc:TODO add retry logic
- rc = umount(tmp_path.c_str());
- if (rc) {
- KLOG_ERROR(TAG, "umount %s failed with rc %d, msg %s\n",
- tmp_path.c_str(), rc, strerror(errno));
- return rc;
- }
-
- // ext4enc:TODO add retry logic
- rc = umount(path);
- if (rc) {
- KLOG_ERROR(TAG, "umount %s failed with rc %d, msg %s\n",
- path, rc, strerror(errno));
- return rc;
- }
-
- return 0;
-}
-
-const char* e4crypt_get_password(const char* path)
-{
- // ext4enc:TODO scrub password after timeout
- auto i = s_password_store.find(path);
- if (i == s_password_store.end()) {
- return 0;
- } else {
- return i->second.c_str();
- }
+ UnencryptedProperties props(dir);
+ return props.Get<int>(properties::is_default, 1) != 1;
}