1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ext4_utils/ext4_crypt.h" 18 19#include <asm/ioctl.h> 20#include <dirent.h> 21#include <errno.h> 22#include <fcntl.h> 23#include <string.h> 24#include <sys/syscall.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27#include <unistd.h> 28 29#include <android-base/file.h> 30#include <android-base/logging.h> 31#include <cutils/properties.h> 32 33#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy" 34#define EXT4_KEYREF_DELIMITER ((char)'.') 35 36// ext4enc:TODO Include structure from somewhere sensible 37// MUST be in sync with ext4_crypto.c in kernel 38#define EXT4_KEY_DESCRIPTOR_SIZE 8 39#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 40 41struct ext4_encryption_policy { 42 uint8_t version; 43 uint8_t contents_encryption_mode; 44 uint8_t filenames_encryption_mode; 45 uint8_t flags; 46 uint8_t master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; 47} __attribute__((__packed__)); 48 49#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 50#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 51#define EXT4_ENCRYPTION_MODE_AES_256_HEH 126 52#define EXT4_ENCRYPTION_MODE_PRIVATE 127 53 54#define EXT4_POLICY_FLAGS_PAD_4 0x00 55#define EXT4_POLICY_FLAGS_PAD_8 0x01 56#define EXT4_POLICY_FLAGS_PAD_16 0x02 57#define EXT4_POLICY_FLAGS_PAD_32 0x03 58#define EXT4_POLICY_FLAGS_PAD_MASK 0x03 59#define EXT4_POLICY_FLAGS_VALID 0x03 60 61// ext4enc:TODO Get value from somewhere sensible 62#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) 63#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) 64 65#define HEX_LOOKUP "0123456789abcdef" 66 67bool e4crypt_is_native() { 68 char value[PROPERTY_VALUE_MAX]; 69 property_get("ro.crypto.type", value, "none"); 70 return !strcmp(value, "file"); 71} 72 73static void policy_to_hex(const char* policy, char* hex) { 74 for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) { 75 hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4]; 76 hex[j++] = HEX_LOOKUP[policy[i] & 0x0F]; 77 } 78 hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0'; 79} 80 81static bool is_dir_empty(const char *dirname, bool *is_empty) 82{ 83 int n = 0; 84 auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir); 85 if (!dirp) { 86 PLOG(ERROR) << "Unable to read directory: " << dirname; 87 return false; 88 } 89 for (;;) { 90 errno = 0; 91 auto entry = readdir(dirp.get()); 92 if (!entry) { 93 if (errno) { 94 PLOG(ERROR) << "Unable to read directory: " << dirname; 95 return false; 96 } 97 break; 98 } 99 if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found 100 ++n; 101 if (n > 2) { 102 *is_empty = false; 103 return true; 104 } 105 } 106 } 107 *is_empty = true; 108 return true; 109} 110 111static uint8_t e4crypt_get_policy_flags(int filenames_encryption_mode) { 112 113 // With HEH, pad filenames with zeroes to the next 16-byte boundary. This 114 // is not required, but it's more secure (helps hide the length of 115 // filenames), makes the inputs evenly divisible into blocks which is more 116 // efficient for encryption and decryption, and we had the opportunity to 117 // make a breaking change when introducing a new mode anyway. 118 if (filenames_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_HEH) { 119 return EXT4_POLICY_FLAGS_PAD_16; 120 } 121 122 // Default flags (4-byte padding) for CTS 123 return EXT4_POLICY_FLAGS_PAD_4; 124} 125 126static bool e4crypt_policy_set(const char *directory, const char *policy, 127 size_t policy_length, 128 int contents_encryption_mode, 129 int filenames_encryption_mode) { 130 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 131 LOG(ERROR) << "Policy wrong length: " << policy_length; 132 return false; 133 } 134 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 135 if (fd == -1) { 136 PLOG(ERROR) << "Failed to open directory " << directory; 137 return false; 138 } 139 140 ext4_encryption_policy eep; 141 eep.version = 0; 142 eep.contents_encryption_mode = contents_encryption_mode; 143 eep.filenames_encryption_mode = filenames_encryption_mode; 144 eep.flags = e4crypt_get_policy_flags(filenames_encryption_mode); 145 memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE); 146 if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) { 147 PLOG(ERROR) << "Failed to set encryption policy for " << directory; 148 close(fd); 149 return false; 150 } 151 close(fd); 152 153 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 154 policy_to_hex(policy, policy_hex); 155 LOG(INFO) << "Policy for " << directory << " set to " << policy_hex; 156 return true; 157} 158 159static bool e4crypt_policy_get(const char *directory, char *policy, 160 size_t policy_length, 161 int contents_encryption_mode, 162 int filenames_encryption_mode) { 163 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 164 LOG(ERROR) << "Policy wrong length: " << policy_length; 165 return false; 166 } 167 168 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 169 if (fd == -1) { 170 PLOG(ERROR) << "Failed to open directory " << directory; 171 return false; 172 } 173 174 ext4_encryption_policy eep; 175 memset(&eep, 0, sizeof(ext4_encryption_policy)); 176 if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) { 177 PLOG(ERROR) << "Failed to get encryption policy for " << directory; 178 close(fd); 179 return false; 180 } 181 close(fd); 182 183 if ((eep.version != 0) 184 || (eep.contents_encryption_mode != contents_encryption_mode) 185 || (eep.filenames_encryption_mode != filenames_encryption_mode) 186 || (eep.flags != 187 e4crypt_get_policy_flags(filenames_encryption_mode))) { 188 LOG(ERROR) << "Failed to find matching encryption policy for " << directory; 189 return false; 190 } 191 memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE); 192 193 return true; 194} 195 196static bool e4crypt_policy_check(const char *directory, const char *policy, 197 size_t policy_length, 198 int contents_encryption_mode, 199 int filenames_encryption_mode) { 200 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 201 LOG(ERROR) << "Policy wrong length: " << policy_length; 202 return false; 203 } 204 char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE]; 205 if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE, 206 contents_encryption_mode, 207 filenames_encryption_mode)) return false; 208 char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 209 210 policy_to_hex(existing_policy, existing_policy_hex); 211 212 if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) != 0) { 213 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 214 policy_to_hex(policy, policy_hex); 215 LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory 216 << " which doesn't match expected value " << policy_hex; 217 return false; 218 } 219 LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory 220 << " which matches expected value"; 221 return true; 222} 223 224int e4crypt_policy_ensure(const char *directory, const char *policy, 225 size_t policy_length, 226 const char *contents_encryption_mode, 227 const char *filenames_encryption_mode) { 228 int contents_mode = 0; 229 int filenames_mode = 0; 230 231 if (!strcmp(contents_encryption_mode, "software") || 232 !strcmp(contents_encryption_mode, "aes-256-xts")) { 233 contents_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; 234 } else if (!strcmp(contents_encryption_mode, "ice")) { 235 contents_mode = EXT4_ENCRYPTION_MODE_PRIVATE; 236 } else { 237 LOG(ERROR) << "Invalid file contents encryption mode: " 238 << contents_encryption_mode; 239 return -1; 240 } 241 242 if (!strcmp(filenames_encryption_mode, "aes-256-cts")) { 243 filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS; 244 } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) { 245 filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_HEH; 246 } else { 247 LOG(ERROR) << "Invalid file names encryption mode: " 248 << filenames_encryption_mode; 249 return -1; 250 } 251 252 bool is_empty; 253 if (!is_dir_empty(directory, &is_empty)) return -1; 254 if (is_empty) { 255 if (!e4crypt_policy_set(directory, policy, policy_length, 256 contents_mode, filenames_mode)) return -1; 257 } else { 258 if (!e4crypt_policy_check(directory, policy, policy_length, 259 contents_mode, filenames_mode)) return -1; 260 } 261 return 0; 262} 263