summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-20 00:22:25 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-20 00:22:25 +0000
commita5b146dbc25f22636c8684863fd64224e9d1f5b6 (patch)
tree3bbb3213b85db29bdf4a455c0ef5e6b9603b5931
parent415e2d4c391701f581279ed8939f16b06bc2335c (diff)
parent150254821a6c989a2cdd31c5dd930b72ef01b73d (diff)
downloadextras-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.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));
}