diff options
author | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-02-20 00:22:25 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-02-20 00:22:25 +0000 |
commit | a5b146dbc25f22636c8684863fd64224e9d1f5b6 (patch) | |
tree | 3bbb3213b85db29bdf4a455c0ef5e6b9603b5931 | |
parent | 415e2d4c391701f581279ed8939f16b06bc2335c (diff) | |
parent | 150254821a6c989a2cdd31c5dd930b72ef01b73d (diff) | |
download | extras-a5b146dbc25f22636c8684863fd64224e9d1f5b6.tar.gz |
Merge "fscrypt option parsing depends on ro.product.first_api_level" am: c96804e159 am: db81f824fc am: 150254821a
Change-Id: I811acf0484c8a23a124f487025eed80898d2a3cd
-rw-r--r-- | libfscrypt/fscrypt.cpp | 63 | ||||
-rw-r--r-- | libfscrypt/include/fscrypt/fscrypt.h | 8 | ||||
-rw-r--r-- | libfscrypt/tests/fscrypt_test.cpp | 237 |
3 files changed, 188 insertions, 120 deletions
diff --git a/libfscrypt/fscrypt.cpp b/libfscrypt/fscrypt.cpp index 9ea8cd33..b8e6ddcf 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/properties.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <asm/ioctl.h> @@ -137,7 +138,16 @@ bool operator!=(const EncryptionOptions& lhs, const EncryptionOptions& rhs) { (lhs.use_hw_wrapped_key == rhs.use_hw_wrapped_key)); } +unsigned int GetFirstApiLevel() { + return android::base::GetUintProperty<unsigned int>("ro.product.first_api_level", 0); +} + bool OptionsToString(const EncryptionOptions& options, std::string* options_string) { + return OptionsToStringForApiLevel(GetFirstApiLevel(), options, options_string); +} + +bool OptionsToStringForApiLevel(unsigned int first_api_level, const EncryptionOptions& options, + std::string* options_string) { std::string contents_mode, filenames_mode; if (!LookupModeById(contents_modes, options.contents_mode, &contents_mode)) { return false; @@ -152,8 +162,9 @@ bool OptionsToString(const EncryptionOptions& options, std::string* options_stri if (options.use_hw_wrapped_key) { *options_string += "+wrappedkey_v0"; } + EncryptionOptions options_check; - if (!ParseOptions(*options_string, &options_check)) { + if (!ParseOptionsForApiLevel(first_api_level, *options_string, &options_check)) { LOG(ERROR) << "Internal error serializing options as string: " << *options_string; return false; } @@ -166,28 +177,41 @@ bool OptionsToString(const EncryptionOptions& options, std::string* options_stri } bool ParseOptions(const std::string& options_string, EncryptionOptions* options) { - memset(options, '\0', sizeof(*options)); + return ParseOptionsForApiLevel(GetFirstApiLevel(), options_string, options); +} + +bool ParseOptionsForApiLevel(unsigned int first_api_level, const std::string& options_string, + EncryptionOptions* options) { auto parts = android::base::Split(options_string, ":"); - if (parts.size() < 1 || parts.size() > 3) { + if (parts.size() > 3) { + LOG(ERROR) << "Invalid encryption options: " << options; return false; } - if (!LookupModeByName(contents_modes, parts[0], &options->contents_mode)) { - LOG(ERROR) << "Invalid file contents encryption mode: " << parts[0]; - return false; - } - if (parts.size() >= 2) { - if (!LookupModeByName(filenames_modes, parts[1], &options->filenames_mode)) { - LOG(ERROR) << "Invalid file names encryption mode: " << parts[1]; + options->contents_mode = FSCRYPT_MODE_AES_256_XTS; + if (parts.size() > 0 && !parts[0].empty()) { + if (!LookupModeByName(contents_modes, parts[0], &options->contents_mode)) { + LOG(ERROR) << "Invalid file contents encryption mode: " << parts[0]; return false; } - } else if (options->contents_mode == FSCRYPT_MODE_ADIANTUM) { + } + if (options->contents_mode == FSCRYPT_MODE_ADIANTUM) { options->filenames_mode = FSCRYPT_MODE_ADIANTUM; } else { options->filenames_mode = FSCRYPT_MODE_AES_256_CTS; } - options->version = 1; + if (parts.size() > 1 && !parts[1].empty()){ + if (!LookupModeByName(filenames_modes, parts[1], &options->filenames_mode)) { + LOG(ERROR) << "Invalid file names encryption mode: " << parts[1]; + return false; + } + } + // Default to v2 after Q + constexpr unsigned int pre_gki_level = 29; + auto is_gki = first_api_level > pre_gki_level; + options->version = is_gki ? 2 : 1; options->flags = 0; - if (parts.size() >= 3) { + options->use_hw_wrapped_key = false; + if (parts.size() > 2 && !parts[2].empty()) { auto flags = android::base::Split(parts[2], "+"); for (const auto& flag : flags) { if (flag == "v1") { @@ -206,12 +230,12 @@ bool ParseOptions(const std::string& options_string, EncryptionOptions* options) } // In the original setting of v1 policies and AES-256-CTS we used 4-byte - // padding of filenames, so we have to retain that for compatibility. + // padding of filenames, so retain that on old first_api_levels. // // 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 (options->version == 1 && options->filenames_mode == FSCRYPT_MODE_AES_256_CTS) { + if (!is_gki && options->version == 1 && options->filenames_mode == FSCRYPT_MODE_AES_256_CTS) { options->flags |= FSCRYPT_POLICY_FLAGS_PAD_4; } else { options->flags |= FSCRYPT_POLICY_FLAGS_PAD_16; @@ -220,8 +244,15 @@ bool ParseOptions(const std::string& options_string, EncryptionOptions* options) // 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 (options->filenames_mode == FSCRYPT_MODE_ADIANTUM) { + if (options->contents_mode == FSCRYPT_MODE_ADIANTUM) { + if (options->filenames_mode != FSCRYPT_MODE_ADIANTUM) { + LOG(ERROR) << "Adiantum must be both contents and filenames mode or neither, invalid options: " << options_string; + return false; + } options->flags |= FSCRYPT_POLICY_FLAG_DIRECT_KEY; + } else if (options->filenames_mode == FSCRYPT_MODE_ADIANTUM) { + LOG(ERROR) << "Adiantum must be both contents and filenames mode or neither, invalid options: " << options_string; + return false; } return true; } diff --git a/libfscrypt/include/fscrypt/fscrypt.h b/libfscrypt/include/fscrypt/fscrypt.h index 18fb4fc3..c780c7ce 100644 --- a/libfscrypt/include/fscrypt/fscrypt.h +++ b/libfscrypt/include/fscrypt/fscrypt.h @@ -47,10 +47,18 @@ struct EncryptionPolicy { void BytesToHex(const std::string& bytes, std::string* hex); +unsigned int GetFirstApiLevel(); + bool OptionsToString(const EncryptionOptions& options, std::string* options_string); +bool OptionsToStringForApiLevel(unsigned int first_api_level, const EncryptionOptions& options, + std::string* options_string); + bool ParseOptions(const std::string& options_string, EncryptionOptions* options); +bool ParseOptionsForApiLevel(unsigned int first_api_level, const std::string& options_string, + EncryptionOptions* options); + bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory); } // namespace fscrypt diff --git a/libfscrypt/tests/fscrypt_test.cpp b/libfscrypt/tests/fscrypt_test.cpp index 379e827b..7149e7ca 100644 --- a/libfscrypt/tests/fscrypt_test.cpp +++ b/libfscrypt/tests/fscrypt_test.cpp @@ -26,113 +26,142 @@ using namespace android::fscrypt; #define FSCRYPT_MODE_AES_256_HEH 126 #define FSCRYPT_MODE_PRIVATE 127 -TEST(fscrypt, ParseOptions) { +const EncryptionOptions TestString(unsigned int first_api_level, const std::string instring, + const std::string outstring) { EncryptionOptions options; std::string options_string; - EXPECT_FALSE(ParseOptions("", &options)); - EXPECT_FALSE(ParseOptions("blah", &options)); - - EXPECT_TRUE(ParseOptions("software", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string); - - EXPECT_TRUE(ParseOptions("aes-256-xts", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string); - - EXPECT_TRUE(ParseOptions("adiantum", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_DIRECT_KEY, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("adiantum:adiantum:v1", options_string); - - EXPECT_TRUE(ParseOptions("adiantum:aes-256-heh", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_HEH, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("adiantum:aes-256-heh:v1", options_string); - - EXPECT_TRUE(ParseOptions("ice", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("ice:aes-256-cts:v1", options_string); - - EXPECT_FALSE(ParseOptions("ice:blah", &options)); - - EXPECT_TRUE(ParseOptions("ice:aes-256-cts", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("ice:aes-256-cts:v1", options_string); - - EXPECT_TRUE(ParseOptions("ice:aes-256-heh", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_HEH, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("ice:aes-256-heh:v1", options_string); - - EXPECT_TRUE(ParseOptions("ice:adiantum", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_DIRECT_KEY, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("ice:adiantum:v1", options_string); - - EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string); - - EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v1", &options)); - EXPECT_EQ(1, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string); - - EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2", &options)); - EXPECT_EQ(2, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v2", options_string); + EXPECT_TRUE(ParseOptionsForApiLevel(first_api_level, instring, &options)); + EXPECT_TRUE(OptionsToStringForApiLevel(first_api_level, options, &options_string)); + EXPECT_EQ(outstring, options_string); + return options; +} - EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", &options)); - EXPECT_EQ(2, options.version); - EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); - EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); - EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, options.flags); - EXPECT_TRUE(OptionsToString(options, &options_string)); - EXPECT_EQ("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", options_string); +#define TEST_STRING(first_api_level, instring, outstring) \ + SCOPED_TRACE(instring); \ + auto options = TestString(first_api_level, instring, outstring); - EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:", &options)); - EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:foo", &options)); - EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:blah", &options)); - EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:vblah", &options)); +TEST(fscrypt, ParseOptions) { + EncryptionOptions dummy_options; + + std::vector<std::string> defaults = { + "software", + "", + ":", + "::", + "aes-256-xts", + "aes-256-xts:", + "aes-256-xts::", + "aes-256-xts:aes-256-cts", + "aes-256-xts:aes-256-cts:", + ":aes-256-cts", + ":aes-256-cts:", + }; + for (const auto& d : defaults) { + TEST_STRING(29, d, "aes-256-xts:aes-256-cts:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); + } + for (const auto& d : defaults) { + TEST_STRING(30, d, "aes-256-xts:aes-256-cts:v2"); + EXPECT_TRUE(ParseOptionsForApiLevel(30, d, &dummy_options)); + EXPECT_EQ(2, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); + } + + EXPECT_FALSE(ParseOptionsForApiLevel(29, "blah", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "blah", &dummy_options)); + + { + TEST_STRING(29, "::v1", "aes-256-xts:aes-256-cts:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); + } + { + TEST_STRING(30, "::v1", "aes-256-xts:aes-256-cts:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); + } + { + TEST_STRING(29, "::v2", "aes-256-xts:aes-256-cts:v2"); + EXPECT_EQ(2, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); + } + { + TEST_STRING(29, "ice", "ice:aes-256-cts:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); + } + EXPECT_FALSE(ParseOptionsForApiLevel(29, "ice:blah", &dummy_options)); + + { + TEST_STRING(29, "ice:aes-256-cts", "ice:aes-256-cts:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_4, options.flags); + } + + { + TEST_STRING(29, "ice:aes-256-heh", "ice:aes-256-heh:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_PRIVATE, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_HEH, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16, options.flags); + } + { + TEST_STRING(29, "adiantum", "adiantum:adiantum:v1"); + EXPECT_EQ(1, options.version); + EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_DIRECT_KEY, options.flags); + } + { + TEST_STRING(30, "adiantum", "adiantum:adiantum:v2"); + EXPECT_EQ(2, options.version); + EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_ADIANTUM, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_DIRECT_KEY, options.flags); + } + EXPECT_FALSE(ParseOptionsForApiLevel(29, "adiantum:aes-256-cts", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "adiantum:aes-256-cts", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(29, "aes-256-xts:adiantum", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "aes-256-xts:adiantum", &dummy_options)); + { + TEST_STRING(30, "::inlinecrypt_optimized", + "aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized"); + EXPECT_EQ(2, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, options.flags); + } + { + TEST_STRING(30, "aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", + "aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized"); + EXPECT_EQ(2, options.version); + EXPECT_EQ(FSCRYPT_MODE_AES_256_XTS, options.contents_mode); + EXPECT_EQ(FSCRYPT_MODE_AES_256_CTS, options.filenames_mode); + EXPECT_EQ(FSCRYPT_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, options.flags); + } + + EXPECT_FALSE(ParseOptionsForApiLevel(29, "aes-256-xts:aes-256-cts:v2:", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(29, "aes-256-xts:aes-256-cts:v2:foo", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(29, "aes-256-xts:aes-256-cts:blah", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(29, "aes-256-xts:aes-256-cts:vblah", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "aes-256-xts:aes-256-cts:v2:", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "aes-256-xts:aes-256-cts:v2:foo", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "aes-256-xts:aes-256-cts:blah", &dummy_options)); + EXPECT_FALSE(ParseOptionsForApiLevel(30, "aes-256-xts:aes-256-cts:vblah", &dummy_options)); } |