1377cd1957172c19ee21baa3d6bda0840f1ce020dPaul Lawrence/*
28d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * Copyright (C) 2015 The Android Open Source Project
38d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley *
48d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * Licensed under the Apache License, Version 2.0 (the "License");
58d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * you may not use this file except in compliance with the License.
68d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * You may obtain a copy of the License at
78d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley *
88d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley *      http://www.apache.org/licenses/LICENSE-2.0
98d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley *
108d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * Unless required by applicable law or agreed to in writing, software
118d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * distributed under the License is distributed on an "AS IS" BASIS,
128d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * See the License for the specific language governing permissions and
148d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley * limitations under the License.
15377cd1957172c19ee21baa3d6bda0840f1ce020dPaul Lawrence */
1692da49db65ffbe0bff1771ecef87ad49e94a0626Paul Lawrence
1706ca811e9297e28f43d65f30493df88862ff09c1Tao Bao#include "ext4_utils/ext4_crypt.h"
18af2359fdc4a45fcf482d1a316bae1fff226c425bPaul Lawrence
1906ca811e9297e28f43d65f30493df88862ff09c1Tao Bao#include <asm/ioctl.h>
204818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <dirent.h>
214818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <errno.h>
224818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <fcntl.h>
2306ca811e9297e28f43d65f30493df88862ff09c1Tao Bao#include <string.h>
244818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <sys/syscall.h>
254818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <sys/stat.h>
264818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <sys/types.h>
2706ca811e9297e28f43d65f30493df88862ff09c1Tao Bao#include <unistd.h>
284818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
29c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence#include <android-base/file.h>
304818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#include <android-base/logging.h>
318d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley#include <cutils/properties.h>
3292da49db65ffbe0bff1771ecef87ad49e94a0626Paul Lawrence
334818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy"
344818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_KEYREF_DELIMITER ((char)'.')
354818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
364818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence// ext4enc:TODO Include structure from somewhere sensible
374818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence// MUST be in sync with ext4_crypto.c in kernel
384818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_KEY_DESCRIPTOR_SIZE 8
394818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
404818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
414818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrencestruct ext4_encryption_policy {
425a8ebaacab368cece8fd99c86effcb3c82229586Paul Lawrence    uint8_t version;
435a8ebaacab368cece8fd99c86effcb3c82229586Paul Lawrence    uint8_t contents_encryption_mode;
445a8ebaacab368cece8fd99c86effcb3c82229586Paul Lawrence    uint8_t filenames_encryption_mode;
455a8ebaacab368cece8fd99c86effcb3c82229586Paul Lawrence    uint8_t flags;
465a8ebaacab368cece8fd99c86effcb3c82229586Paul Lawrence    uint8_t master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
474818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence} __attribute__((__packed__));
484818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
494818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_ENCRYPTION_MODE_AES_256_XTS    1
504818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_ENCRYPTION_MODE_AES_256_CTS    4
51a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_ENCRYPTION_MODE_AES_256_HEH    126
52c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence#define EXT4_ENCRYPTION_MODE_PRIVATE        127
534818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
54a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_PAD_4         0x00
55a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_PAD_8         0x01
56a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_PAD_16        0x02
57a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_PAD_32        0x03
58a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_PAD_MASK      0x03
59a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers#define EXT4_POLICY_FLAGS_VALID         0x03
60a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
614818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence// ext4enc:TODO Get value from somewhere sensible
624818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
634818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
644818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
654818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence#define HEX_LOOKUP "0123456789abcdef"
664818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
678d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowleybool e4crypt_is_native() {
688d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley    char value[PROPERTY_VALUE_MAX];
698d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley    property_get("ro.crypto.type", value, "none");
708d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley    return !strcmp(value, "file");
718d53b9619ba913354ffdb23acf0108f7445bb8bcPaul Crowley}
724818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
734818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrencestatic void policy_to_hex(const char* policy, char* hex) {
744818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) {
754818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
764818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
774818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
784818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
794818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
804818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
814818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrencestatic bool is_dir_empty(const char *dirname, bool *is_empty)
824818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence{
834818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    int n = 0;
844818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir);
854818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (!dirp) {
864818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        PLOG(ERROR) << "Unable to read directory: " << dirname;
874818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
884818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
894818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    for (;;) {
904818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        errno = 0;
914818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        auto entry = readdir(dirp.get());
924818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        if (!entry) {
934818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            if (errno) {
944818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence                PLOG(ERROR) << "Unable to read directory: " << dirname;
954818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence                return false;
964818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            }
974818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            break;
984818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        }
994818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found
1004818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            ++n;
1014818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            if (n > 2) {
1024818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence                *is_empty = false;
1034818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence                return true;
1044818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence            }
1054818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        }
1064818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1074818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    *is_empty = true;
1084818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    return true;
1094818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
1104818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
111a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggersstatic uint8_t e4crypt_get_policy_flags(int filenames_encryption_mode) {
112a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
113a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // With HEH, pad filenames with zeroes to the next 16-byte boundary.  This
114a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // is not required, but it's more secure (helps hide the length of
115a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // filenames), makes the inputs evenly divisible into blocks which is more
116a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // efficient for encryption and decryption, and we had the opportunity to
117a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // make a breaking change when introducing a new mode anyway.
118a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    if (filenames_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_HEH) {
119a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        return EXT4_POLICY_FLAGS_PAD_16;
120a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    }
121a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
122a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    // Default flags (4-byte padding) for CTS
123a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    return EXT4_POLICY_FLAGS_PAD_4;
124a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers}
125a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
126c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrencestatic bool e4crypt_policy_set(const char *directory, const char *policy,
127a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               size_t policy_length,
128a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               int contents_encryption_mode,
129a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               int filenames_encryption_mode) {
1304818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
1314818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        LOG(ERROR) << "Policy wrong length: " << policy_length;
1324818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1334818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1344818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
1354818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (fd == -1) {
1364818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        PLOG(ERROR) << "Failed to open directory " << directory;
1374818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1384818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1394818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1404818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    ext4_encryption_policy eep;
1414818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    eep.version = 0;
142c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence    eep.contents_encryption_mode = contents_encryption_mode;
143a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    eep.filenames_encryption_mode = filenames_encryption_mode;
144a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    eep.flags = e4crypt_get_policy_flags(filenames_encryption_mode);
1454818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
1464818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
1474818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        PLOG(ERROR) << "Failed to set encryption policy for " << directory;
1484818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        close(fd);
1494818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1504818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1514818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    close(fd);
1524818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1534818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
1544818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    policy_to_hex(policy, policy_hex);
1554818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
1564818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    return true;
1574818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
1584818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
159c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrencestatic bool e4crypt_policy_get(const char *directory, char *policy,
160a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               size_t policy_length,
161a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               int contents_encryption_mode,
162a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                               int filenames_encryption_mode) {
1634818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
1644818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        LOG(ERROR) << "Policy wrong length: " << policy_length;
1654818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1664818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1674818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1684818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
1694818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (fd == -1) {
1704818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        PLOG(ERROR) << "Failed to open directory " << directory;
1714818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1724818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1734818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1744818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    ext4_encryption_policy eep;
1754818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    memset(&eep, 0, sizeof(ext4_encryption_policy));
1764818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) {
1774818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        PLOG(ERROR) << "Failed to get encryption policy for " << directory;
1784818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        close(fd);
17930b93dd5715abcabd621235733733c0503f9c552Ethan Yonker        return false;
1804818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1814818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    close(fd);
1824818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1834818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if ((eep.version != 0)
184c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence            || (eep.contents_encryption_mode != contents_encryption_mode)
185a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers            || (eep.filenames_encryption_mode != filenames_encryption_mode)
186a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers            || (eep.flags !=
187a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                e4crypt_get_policy_flags(filenames_encryption_mode))) {
1884818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
1894818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
1904818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
1914818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE);
1924818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
1934818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    return true;
1944818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
1954818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
196c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrencestatic bool e4crypt_policy_check(const char *directory, const char *policy,
197a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                                 size_t policy_length,
198a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                                 int contents_encryption_mode,
199a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                                 int filenames_encryption_mode) {
2004818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
2014818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        LOG(ERROR) << "Policy wrong length: " << policy_length;
2024818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
2034818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
2044818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE];
205c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence    if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE,
206a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                            contents_encryption_mode,
207a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                            filenames_encryption_mode)) return false;
2084818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
2094818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
2104818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    policy_to_hex(existing_policy, existing_policy_hex);
2114818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
2124818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) != 0) {
2134818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
2144818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        policy_to_hex(policy, policy_hex);
2154818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory
2164818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence                   << " which doesn't match expected value " << policy_hex;
2174818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence        return false;
2184818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
2194818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
2204818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence              << " which matches expected value";
2214818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    return true;
2224818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
2234818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence
224c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrenceint e4crypt_policy_ensure(const char *directory, const char *policy,
225a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                          size_t policy_length,
226a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                          const char *contents_encryption_mode,
227a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                          const char *filenames_encryption_mode) {
228a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    int contents_mode = 0;
229a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    int filenames_mode = 0;
230a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
231a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    if (!strcmp(contents_encryption_mode, "software") ||
232a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        !strcmp(contents_encryption_mode, "aes-256-xts")) {
233a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        contents_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
234c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence    } else if (!strcmp(contents_encryption_mode, "ice")) {
235a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        contents_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
236a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    } else {
237a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        LOG(ERROR) << "Invalid file contents encryption mode: "
238a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                   << contents_encryption_mode;
239a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        return -1;
240a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    }
241a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers
242a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
243a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
244a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers    } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
245a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        filenames_mode = EXT4_ENCRYPTION_MODE_AES_256_HEH;
246c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence    } else {
247a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers        LOG(ERROR) << "Invalid file names encryption mode: "
248a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                   << filenames_encryption_mode;
249c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence        return -1;
250c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence    }
251c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence
2524818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    bool is_empty;
2534818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (!is_dir_empty(directory, &is_empty)) return -1;
2544818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    if (is_empty) {
255c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence        if (!e4crypt_policy_set(directory, policy, policy_length,
256a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                                contents_mode, filenames_mode)) return -1;
2574818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    } else {
258c096c9c65ffd4485f137d1b90cffe280cf96fbc6Paul Lawrence        if (!e4crypt_policy_check(directory, policy, policy_length,
259a9fa60514da82a4bb2d420771b696b4a6d53c024Eric Biggers                                  contents_mode, filenames_mode)) return -1;
2604818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    }
2614818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence    return 0;
2624818b73cf845e05c6b14afb07e38da0b6720865aPaul Lawrence}
263