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 <array> 20 21 #include <asm/ioctl.h> 22 #include <dirent.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <string.h> 26 #include <sys/syscall.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <unistd.h> 30 31 #include <android-base/file.h> 32 #include <android-base/logging.h> 33 #include <cutils/properties.h> 34 #include <logwrap/logwrap.h> 35 #include <utils/misc.h> 36 37 #define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy" 38 #define EXT4_KEYREF_DELIMITER ((char)'.') 39 40 // ext4enc:TODO Include structure from somewhere sensible 41 // MUST be in sync with ext4_crypto.c in kernel 42 #define EXT4_KEY_DESCRIPTOR_SIZE 8 43 #define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 44 45 struct ext4_encryption_policy { 46 uint8_t version; 47 uint8_t contents_encryption_mode; 48 uint8_t filenames_encryption_mode; 49 uint8_t flags; 50 uint8_t master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; 51 } __attribute__((__packed__)); 52 53 #define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 54 #define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 55 #define EXT4_ENCRYPTION_MODE_SPECK128_256_XTS 7 56 #define EXT4_ENCRYPTION_MODE_SPECK128_256_CTS 8 57 #define EXT4_ENCRYPTION_MODE_AES_256_HEH 126 58 #define EXT4_ENCRYPTION_MODE_PRIVATE 127 59 60 #define EXT4_POLICY_FLAGS_PAD_4 0x00 61 #define EXT4_POLICY_FLAGS_PAD_8 0x01 62 #define EXT4_POLICY_FLAGS_PAD_16 0x02 63 #define EXT4_POLICY_FLAGS_PAD_32 0x03 64 #define EXT4_POLICY_FLAGS_PAD_MASK 0x03 65 #define EXT4_POLICY_FLAGS_VALID 0x03 66 67 // ext4enc:TODO Get value from somewhere sensible 68 #define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) 69 #define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) 70 71 #define HEX_LOOKUP "0123456789abcdef" 72 73 bool e4crypt_is_native() { 74 char value[PROPERTY_VALUE_MAX]; 75 property_get("ro.crypto.type", value, "none"); 76 return !strcmp(value, "file"); 77 } 78 79 static void log_ls(const char* dirname) { 80 std::array<const char*, 3> argv = {"ls", "-laZ", dirname}; 81 int status = 0; 82 auto res = 83 android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), &status, false, true); 84 if (res != 0) { 85 PLOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] << "failed"; 86 return; 87 } 88 if (!WIFEXITED(status)) { 89 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] 90 << " did not exit normally, status: " << status; 91 return; 92 } 93 if (WEXITSTATUS(status) != 0) { 94 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] 95 << " returned failure: " << WEXITSTATUS(status); 96 return; 97 } 98 } 99 100 static void policy_to_hex(const char* policy, char* hex) { 101 for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) { 102 hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4]; 103 hex[j++] = HEX_LOOKUP[policy[i] & 0x0F]; 104 } 105 hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0'; 106 } 107 108 static bool is_dir_empty(const char *dirname, bool *is_empty) 109 { 110 int n = 0; 111 auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir); 112 if (!dirp) { 113 PLOG(ERROR) << "Unable to read directory: " << dirname; 114 return false; 115 } 116 for (;;) { 117 errno = 0; 118 auto entry = readdir(dirp.get()); 119 if (!entry) { 120 if (errno) { 121 PLOG(ERROR) << "Unable to read directory: " << dirname; 122 return false; 123 } 124 break; 125 } 126 if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found 127 ++n; 128 if (n > 2) { 129 *is_empty = false; 130 return true; 131 } 132 } 133 } 134 *is_empty = true; 135 return true; 136 } 137 138 static uint8_t e4crypt_get_policy_flags(int filenames_encryption_mode) { 139 if (filenames_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_CTS) { 140 // Use legacy padding with our original filenames encryption mode. 141 return EXT4_POLICY_FLAGS_PAD_4; 142 } 143 // With a new mode we can use the better padding flag without breaking existing devices: pad 144 // filenames with zeroes to the next 16-byte boundary. This is more secure (helps hide the 145 // length of filenames) and makes the inputs evenly divisible into blocks which is more 146 // efficient for encryption and decryption. 147 return EXT4_POLICY_FLAGS_PAD_16; 148 } 149 150 static bool e4crypt_policy_set(const char *directory, const char *policy, 151 size_t policy_length, 152 int contents_encryption_mode, 153 int filenames_encryption_mode) { 154 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 155 LOG(ERROR) << "Policy wrong length: " << policy_length; 156 return false; 157 } 158 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 159 policy_to_hex(policy, policy_hex); 160 161 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 162 if (fd == -1) { 163 PLOG(ERROR) << "Failed to open directory " << directory; 164 return false; 165 } 166 167 ext4_encryption_policy eep; 168 eep.version = 0; 169 eep.contents_encryption_mode = contents_encryption_mode; 170 eep.filenames_encryption_mode = filenames_encryption_mode; 171 eep.flags = e4crypt_get_policy_flags(filenames_encryption_mode); 172 memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE); 173 if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) { 174 PLOG(ERROR) << "Failed to set encryption policy for " << directory << " to " << policy_hex 175 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode; 176 close(fd); 177 return false; 178 } 179 close(fd); 180 181 LOG(INFO) << "Policy for " << directory << " set to " << policy_hex 182 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode; 183 return true; 184 } 185 186 static bool e4crypt_policy_get(const char *directory, char *policy, 187 size_t policy_length, 188 int contents_encryption_mode, 189 int filenames_encryption_mode) { 190 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 191 LOG(ERROR) << "Policy wrong length: " << policy_length; 192 return false; 193 } 194 195 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 196 if (fd == -1) { 197 PLOG(ERROR) << "Failed to open directory " << directory; 198 return false; 199 } 200 201 ext4_encryption_policy eep; 202 memset(&eep, 0, sizeof(ext4_encryption_policy)); 203 if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) { 204 PLOG(ERROR) << "Failed to get encryption policy for " << directory; 205 close(fd); 206 log_ls(directory); 207 return false; 208 } 209 close(fd); 210 211 if ((eep.version != 0) 212 || (eep.contents_encryption_mode != contents_encryption_mode) 213 || (eep.filenames_encryption_mode != filenames_encryption_mode) 214 || (eep.flags != 215 e4crypt_get_policy_flags(filenames_encryption_mode))) { 216 LOG(ERROR) << "Failed to find matching encryption policy for " << directory; 217 return false; 218 } 219 memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE); 220 221 return true; 222 } 223 224 static bool e4crypt_policy_check(const char *directory, const char *policy, 225 size_t policy_length, 226 int contents_encryption_mode, 227 int filenames_encryption_mode) { 228 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 229 LOG(ERROR) << "Policy wrong length: " << policy_length; 230 return false; 231 } 232 char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE]; 233 if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE, 234 contents_encryption_mode, 235 filenames_encryption_mode)) return false; 236 char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 237 238 policy_to_hex(existing_policy, existing_policy_hex); 239 240 if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) != 0) { 241 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 242 policy_to_hex(policy, policy_hex); 243 LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory 244 << " which doesn't match expected value " << policy_hex; 245 log_ls(directory); 246 return false; 247 } 248 LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory 249 << " which matches expected value"; 250 return true; 251 } 252 253 int e4crypt_policy_ensure(const char *directory, const char *policy, 254 size_t policy_length, 255 const char *contents_encryption_mode, 256 const char *filenames_encryption_mode) { 257 int contents_mode = 0; 258 int filenames_mode = 0; 259 260 if (!strcmp(contents_encryption_mode, "software") || 261 !strcmp(contents_encryption_mode, "aes-256-xts")) { 262 contents_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; 263 } else if (!strcmp(contents_encryption_mode, "speck128/256-xts")) { 264 contents_mode = EXT4_ENCRYPTION_MODE_SPECK128_256_XTS; 265 } else if (!strcmp(contents_encryption_mode, "ice")) { 266 contents_mode = EXT4_ENCRYPTION_MODE_PRIVATE; 267 } else { 268 LOG(ERROR) << "Invalid file contents encryption mode: " 269 << contents_encryption_mode; 270 return -1; 271 } 272 273 if (!strcmp(filenames_encryption_mode, "aes-256-cts")) { 274 filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS; 275 } else if (!strcmp(filenames_encryption_mode, "speck128/256-cts")) { 276 filenames_mode = EXT4_ENCRYPTION_MODE_SPECK128_256_CTS; 277 } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) { 278 filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_HEH; 279 } else { 280 LOG(ERROR) << "Invalid file names encryption mode: " 281 << filenames_encryption_mode; 282 return -1; 283 } 284 285 bool is_empty; 286 if (!is_dir_empty(directory, &is_empty)) return -1; 287 if (is_empty) { 288 if (!e4crypt_policy_set(directory, policy, policy_length, 289 contents_mode, filenames_mode)) return -1; 290 } else { 291 if (!e4crypt_policy_check(directory, policy, policy_length, 292 contents_mode, filenames_mode)) return -1; 293 } 294 return 0; 295 } 296