summaryrefslogtreecommitdiff
path: root/libfscrypt
diff options
context:
space:
mode:
authorPaul Crowley <paulcrowley@google.com>2020-02-18 21:30:03 -0800
committerPaul Crowley <paulcrowley@google.com>2020-02-19 12:21:32 -0800
commit47212f0c707c0e81f8de2ab19e9c661addb9eed0 (patch)
tree685a7d1b162f60e04800a5f88621f58e342fff8e /libfscrypt
parentda95b3f323f1ba535be8d583b366f1cfdba8e1c8 (diff)
downloadextras-47212f0c707c0e81f8de2ab19e9c661addb9eed0.tar.gz
fscrypt option parsing depends on ro.product.first_api_level
We'd like to change what the defaults are for fscrypt as we get new and better things, but we don't want to break old devices. So we arrange for the behavior to depend on the API version the device launched with. In addition, we can now supply a default if any of the three fields are blank, meaning that clients like get_volume_file_encryption_options don't have to separately specify defaults. Right now we use the API level to choose between version 1 and version 2 being default, and as a further guard against anyone using the deprecated FSCRYPT_POLICY_FLAGS_PAD_4 on new devices. Bug: 147107322 Test: atest fscrypt Test: Various Cuttlefish configurations Change-Id: I43c94c1051c61d2b051355dcd428c44c279a3c75
Diffstat (limited to 'libfscrypt')
-rw-r--r--libfscrypt/fscrypt.cpp63
-rw-r--r--libfscrypt/include/fscrypt/fscrypt.h8
-rw-r--r--libfscrypt/tests/fscrypt_test.cpp237
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));
}