aboutsummaryrefslogtreecommitdiff
path: root/cc/daead
diff options
context:
space:
mode:
authorwconner <wconner@google.com>2023-06-21 09:08:35 -0700
committerCopybara-Service <copybara-worker@google.com>2023-06-21 09:10:25 -0700
commit1578d8712483251f75572269f3f0470e68bc93b2 (patch)
tree3accf6759974a6c1fe9ff5a1034ce844ac07d6c7 /cc/daead
parent18dc8ea58250ad1a9eeb5e94645adae2e9775b13 (diff)
downloadtink-1578d8712483251f75572269f3f0470e68bc93b2.tar.gz
Add AES-SIV proto serialization.
PiperOrigin-RevId: 542273923
Diffstat (limited to 'cc/daead')
-rw-r--r--cc/daead/BUILD.bazel49
-rw-r--r--cc/daead/CMakeLists.txt47
-rw-r--r--cc/daead/aes_siv_proto_serialization.cc237
-rw-r--r--cc/daead/aes_siv_proto_serialization.h31
-rw-r--r--cc/daead/aes_siv_proto_serialization_test.cc395
5 files changed, 759 insertions, 0 deletions
diff --git a/cc/daead/BUILD.bazel b/cc/daead/BUILD.bazel
index 97427828a..f5ac9691d 100644
--- a/cc/daead/BUILD.bazel
+++ b/cc/daead/BUILD.bazel
@@ -155,6 +155,33 @@ cc_library(
],
)
+cc_library(
+ name = "aes_siv_proto_serialization",
+ srcs = ["aes_siv_proto_serialization.cc"],
+ hdrs = ["aes_siv_proto_serialization.h"],
+ include_prefix = "tink/daead",
+ deps = [
+ ":aes_siv_key",
+ ":aes_siv_parameters",
+ "//:partial_key_access",
+ "//:restricted_data",
+ "//:secret_key_access_token",
+ "//internal:key_parser",
+ "//internal:key_serializer",
+ "//internal:mutable_serialization_registry",
+ "//internal:parameters_parser",
+ "//internal:parameters_serializer",
+ "//internal:proto_key_serialization",
+ "//internal:proto_parameters_serialization",
+ "//proto:aes_siv_cc_proto",
+ "//proto:tink_cc_proto",
+ "//util:status",
+ "//util:statusor",
+ "@com_google_absl//absl/status",
+ "@com_google_absl//absl/types:optional",
+ ],
+)
+
# tests
cc_test(
@@ -288,3 +315,25 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_test(
+ name = "aes_siv_proto_serialization_test",
+ size = "small",
+ srcs = ["aes_siv_proto_serialization_test.cc"],
+ deps = [
+ ":aes_siv_key",
+ ":aes_siv_parameters",
+ ":aes_siv_proto_serialization",
+ "//:insecure_secret_key_access",
+ "//:partial_key_access",
+ "//:restricted_data",
+ "//internal:mutable_serialization_registry",
+ "//internal:proto_key_serialization",
+ "//internal:proto_parameters_serialization",
+ "//proto:aes_siv_cc_proto",
+ "//proto:tink_cc_proto",
+ "//subtle:random",
+ "//util:test_matchers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/cc/daead/CMakeLists.txt b/cc/daead/CMakeLists.txt
index 3a1efc047..39210717b 100644
--- a/cc/daead/CMakeLists.txt
+++ b/cc/daead/CMakeLists.txt
@@ -145,6 +145,32 @@ tink_cc_library(
tink::util::statusor
)
+tink_cc_library(
+ NAME aes_siv_proto_serialization
+ SRCS
+ aes_siv_proto_serialization.cc
+ aes_siv_proto_serialization.h
+ DEPS
+ tink::daead::aes_siv_key
+ tink::daead::aes_siv_parameters
+ absl::status
+ absl::optional
+ tink::core::partial_key_access
+ tink::core::restricted_data
+ tink::core::secret_key_access_token
+ tink::internal::key_parser
+ tink::internal::key_serializer
+ tink::internal::mutable_serialization_registry
+ tink::internal::parameters_parser
+ tink::internal::parameters_serializer
+ tink::internal::proto_key_serialization
+ tink::internal::proto_parameters_serialization
+ tink::util::status
+ tink::util::statusor
+ tink::proto::aes_siv_cc_proto
+ tink::proto::tink_cc_proto
+)
+
# tests
tink_cc_test(
@@ -272,3 +298,24 @@ tink_cc_test(
tink::util::statusor
tink::util::test_matchers
)
+
+tink_cc_test(
+ NAME aes_siv_proto_serialization_test
+ SRCS
+ aes_siv_proto_serialization_test.cc
+ DEPS
+ tink::daead::aes_siv_key
+ tink::daead::aes_siv_parameters
+ tink::daead::aes_siv_proto_serialization
+ gmock
+ tink::core::insecure_secret_key_access
+ tink::core::partial_key_access
+ tink::core::restricted_data
+ tink::internal::mutable_serialization_registry
+ tink::internal::proto_key_serialization
+ tink::internal::proto_parameters_serialization
+ tink::subtle::random
+ tink::util::test_matchers
+ tink::proto::aes_siv_cc_proto
+ tink::proto::tink_cc_proto
+)
diff --git a/cc/daead/aes_siv_proto_serialization.cc b/cc/daead/aes_siv_proto_serialization.cc
new file mode 100644
index 000000000..c1711c5ac
--- /dev/null
+++ b/cc/daead/aes_siv_proto_serialization.cc
@@ -0,0 +1,237 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "tink/daead/aes_siv_proto_serialization.h"
+
+#include <string>
+
+#include "absl/status/status.h"
+#include "absl/types/optional.h"
+#include "tink/daead/aes_siv_key.h"
+#include "tink/daead/aes_siv_parameters.h"
+#include "tink/internal/key_parser.h"
+#include "tink/internal/key_serializer.h"
+#include "tink/internal/mutable_serialization_registry.h"
+#include "tink/internal/parameters_parser.h"
+#include "tink/internal/parameters_serializer.h"
+#include "tink/internal/proto_key_serialization.h"
+#include "tink/internal/proto_parameters_serialization.h"
+#include "tink/partial_key_access.h"
+#include "tink/restricted_data.h"
+#include "tink/secret_key_access_token.h"
+#include "tink/util/status.h"
+#include "tink/util/statusor.h"
+#include "proto/aes_siv.pb.h"
+#include "proto/tink.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::google::crypto::tink::AesSivKeyFormat;
+using ::google::crypto::tink::OutputPrefixType;
+
+using AesSivProtoParametersParserImpl =
+ internal::ParametersParserImpl<internal::ProtoParametersSerialization,
+ AesSivParameters>;
+using AesSivProtoParametersSerializerImpl =
+ internal::ParametersSerializerImpl<AesSivParameters,
+ internal::ProtoParametersSerialization>;
+using AesSivProtoKeyParserImpl =
+ internal::KeyParserImpl<internal::ProtoKeySerialization, AesSivKey>;
+using AesSivProtoKeySerializerImpl =
+ internal::KeySerializerImpl<AesSivKey, internal::ProtoKeySerialization>;
+
+const absl::string_view kTypeUrl =
+ "type.googleapis.com/google.crypto.tink.AesSivKey";
+
+util::StatusOr<AesSivParameters::Variant> ToVariant(
+ OutputPrefixType output_prefix_type) {
+ switch (output_prefix_type) {
+ case OutputPrefixType::LEGACY:
+ ABSL_FALLTHROUGH_INTENDED; // Parse LEGACY output prefix as CRUNCHY.
+ case OutputPrefixType::CRUNCHY:
+ return AesSivParameters::Variant::kCrunchy;
+ case OutputPrefixType::RAW:
+ return AesSivParameters::Variant::kNoPrefix;
+ case OutputPrefixType::TINK:
+ return AesSivParameters::Variant::kTink;
+ default:
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Could not determine AesSivParameters::Variant");
+ }
+}
+
+util::StatusOr<OutputPrefixType> ToOutputPrefixType(
+ AesSivParameters::Variant variant) {
+ switch (variant) {
+ case AesSivParameters::Variant::kCrunchy:
+ return OutputPrefixType::CRUNCHY;
+ case AesSivParameters::Variant::kNoPrefix:
+ return OutputPrefixType::RAW;
+ case AesSivParameters::Variant::kTink:
+ return OutputPrefixType::TINK;
+ default:
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Could not determine output prefix type");
+ }
+}
+
+util::StatusOr<AesSivParameters> ParseParameters(
+ const internal::ProtoParametersSerialization& serialization) {
+ if (serialization.GetKeyTemplate().type_url() != kTypeUrl) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Wrong type URL when parsing AesSivParameters.");
+ }
+
+ AesSivKeyFormat proto_key_format;
+ if (!proto_key_format.ParseFromString(
+ serialization.GetKeyTemplate().value())) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Failed to parse AesSivKeyFormat proto");
+ }
+ if (proto_key_format.version() != 0) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Only version 0 keys are accepted.");
+ }
+
+ util::StatusOr<AesSivParameters::Variant> variant =
+ ToVariant(serialization.GetKeyTemplate().output_prefix_type());
+ if (!variant.ok()) return variant.status();
+
+ return AesSivParameters::Create(proto_key_format.key_size(), *variant);
+}
+
+util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
+ const AesSivParameters& parameters) {
+ util::StatusOr<OutputPrefixType> output_prefix_type =
+ ToOutputPrefixType(parameters.GetVariant());
+ if (!output_prefix_type.ok()) return output_prefix_type.status();
+
+ AesSivKeyFormat proto_key_format;
+ proto_key_format.set_key_size(parameters.KeySizeInBytes());
+
+ return internal::ProtoParametersSerialization::Create(
+ kTypeUrl, *output_prefix_type, proto_key_format.SerializeAsString());
+}
+
+util::StatusOr<AesSivKey> ParseKey(
+ const internal::ProtoKeySerialization& serialization,
+ absl::optional<SecretKeyAccessToken> token) {
+ if (serialization.TypeUrl() != kTypeUrl) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Wrong type URL when parsing AesSivKey.");
+ }
+ if (!token.has_value()) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "SecretKeyAccess is required");
+ }
+ google::crypto::tink::AesSivKey proto_key;
+ RestrictedData restricted_data = serialization.SerializedKeyProto();
+ // OSS proto library complains if input is not converted to a string.
+ if (!proto_key.ParseFromString(
+ std::string(restricted_data.GetSecret(*token)))) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Failed to parse AesSivKey proto");
+ }
+ if (proto_key.version() != 0) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Only version 0 keys are accepted.");
+ }
+
+ util::StatusOr<AesSivParameters::Variant> variant =
+ ToVariant(serialization.GetOutputPrefixType());
+ if (!variant.ok()) return variant.status();
+
+ util::StatusOr<AesSivParameters> parameters =
+ AesSivParameters::Create(proto_key.key_value().length(), *variant);
+ if (!parameters.ok()) return parameters.status();
+
+ return AesSivKey::Create(
+ *parameters, RestrictedData(proto_key.key_value(), *token),
+ serialization.IdRequirement(), GetPartialKeyAccess());
+}
+
+util::StatusOr<internal::ProtoKeySerialization> SerializeKey(
+ const AesSivKey& key, absl::optional<SecretKeyAccessToken> token) {
+ util::StatusOr<RestrictedData> restricted_input =
+ key.GetKeyBytes(GetPartialKeyAccess());
+ if (!restricted_input.ok()) return restricted_input.status();
+ if (!token.has_value()) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "SecretKeyAccess is required");
+ }
+
+ google::crypto::tink::AesSivKey proto_key;
+ proto_key.set_version(0);
+ // OSS proto library complains if input is not converted to a string.
+ proto_key.set_key_value(std::string(restricted_input->GetSecret(*token)));
+
+ util::StatusOr<OutputPrefixType> output_prefix_type =
+ ToOutputPrefixType(key.GetParameters().GetVariant());
+ if (!output_prefix_type.ok()) return output_prefix_type.status();
+
+ RestrictedData restricted_output =
+ RestrictedData(proto_key.SerializeAsString(), *token);
+ return internal::ProtoKeySerialization::Create(
+ kTypeUrl, restricted_output, google::crypto::tink::KeyData::SYMMETRIC,
+ *output_prefix_type, key.GetIdRequirement());
+}
+
+AesSivProtoParametersParserImpl* AesSivProtoParametersParser() {
+ static auto* parser =
+ new AesSivProtoParametersParserImpl(kTypeUrl, ParseParameters);
+ return parser;
+}
+
+AesSivProtoParametersSerializerImpl* AesSivProtoParametersSerializer() {
+ static auto* serializer =
+ new AesSivProtoParametersSerializerImpl(kTypeUrl, SerializeParameters);
+ return serializer;
+}
+
+AesSivProtoKeyParserImpl* AesSivProtoKeyParser() {
+ static auto* parser = new AesSivProtoKeyParserImpl(kTypeUrl, ParseKey);
+ return parser;
+}
+
+AesSivProtoKeySerializerImpl* AesSivProtoKeySerializer() {
+ static auto* serializer = new AesSivProtoKeySerializerImpl(SerializeKey);
+ return serializer;
+}
+
+} // namespace
+
+util::Status RegisterAesSivProtoSerialization() {
+ util::Status status =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterParametersParser(AesSivProtoParametersParser());
+ if (!status.ok()) return status;
+
+ status = internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterParametersSerializer(AesSivProtoParametersSerializer());
+ if (!status.ok()) return status;
+
+ status = internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterKeyParser(AesSivProtoKeyParser());
+ if (!status.ok()) return status;
+
+ return internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterKeySerializer(AesSivProtoKeySerializer());
+}
+
+} // namespace tink
+} // namespace crypto
diff --git a/cc/daead/aes_siv_proto_serialization.h b/cc/daead/aes_siv_proto_serialization.h
new file mode 100644
index 000000000..daff86719
--- /dev/null
+++ b/cc/daead/aes_siv_proto_serialization.h
@@ -0,0 +1,31 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef TINK_DAEAD_AES_SIV_PROTO_SERIALIZATION_H_
+#define TINK_DAEAD_AES_SIV_PROTO_SERIALIZATION_H_
+
+#include "tink/util/status.h"
+
+namespace crypto {
+namespace tink {
+
+// Registers proto parsers and serializers for AES-SIV parameters and keys.
+crypto::tink::util::Status RegisterAesSivProtoSerialization();
+
+} // namespace tink
+} // namespace crypto
+
+#endif // TINK_DAEAD_AES_SIV_PROTO_SERIALIZATION_H_
diff --git a/cc/daead/aes_siv_proto_serialization_test.cc b/cc/daead/aes_siv_proto_serialization_test.cc
new file mode 100644
index 000000000..1f6a45a3d
--- /dev/null
+++ b/cc/daead/aes_siv_proto_serialization_test.cc
@@ -0,0 +1,395 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "tink/daead/aes_siv_proto_serialization.h"
+
+#include <memory>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "tink/daead/aes_siv_key.h"
+#include "tink/daead/aes_siv_parameters.h"
+#include "tink/insecure_secret_key_access.h"
+#include "tink/internal/mutable_serialization_registry.h"
+#include "tink/internal/proto_key_serialization.h"
+#include "tink/internal/proto_parameters_serialization.h"
+#include "tink/partial_key_access.h"
+#include "tink/restricted_data.h"
+#include "tink/subtle/random.h"
+#include "tink/util/test_matchers.h"
+#include "proto/aes_siv.pb.h"
+#include "proto/tink.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::crypto::tink::subtle::Random;
+using ::crypto::tink::test::IsOk;
+using ::crypto::tink::test::IsOkAndHolds;
+using ::crypto::tink::test::StatusIs;
+using ::google::crypto::tink::AesSivKeyFormat;
+using ::google::crypto::tink::KeyData;
+using ::google::crypto::tink::OutputPrefixType;
+using ::testing::Eq;
+using ::testing::IsTrue;
+using ::testing::NotNull;
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+struct TestCase {
+ AesSivParameters::Variant variant;
+ OutputPrefixType output_prefix_type;
+ int key_size;
+ absl::optional<int> id;
+ std::string output_prefix;
+};
+
+class AesSivProtoSerializationTest : public TestWithParam<TestCase> {
+ protected:
+ void SetUp() override {
+ internal::MutableSerializationRegistry::GlobalInstance().Reset();
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ AesSivProtoSerializationTestSuite, AesSivProtoSerializationTest,
+ Values(TestCase{AesSivParameters::Variant::kTink, OutputPrefixType::TINK,
+ /*key_size=*/32, /*id=*/0x02030400,
+ /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
+ TestCase{AesSivParameters::Variant::kCrunchy,
+ OutputPrefixType::CRUNCHY, /*key_size=*/48,
+ /*id=*/0x01030005,
+ /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
+ TestCase{AesSivParameters::Variant::kNoPrefix, OutputPrefixType::RAW,
+ /*key_size=*/64, /*id=*/absl::nullopt,
+ /*output_prefix=*/""}));
+
+TEST_P(AesSivProtoSerializationTest, ParseParameters) {
+ TestCase test_case = GetParam();
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ AesSivKeyFormat key_format_proto;
+ key_format_proto.set_version(0);
+ key_format_proto.set_key_size(test_case.key_size);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey",
+ test_case.output_prefix_type, key_format_proto.SerializeAsString());
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ ASSERT_THAT(params, IsOk());
+ EXPECT_THAT((*params)->HasIdRequirement(), test_case.id.has_value());
+
+ const AesSivParameters* siv_params =
+ dynamic_cast<const AesSivParameters*>(params->get());
+ ASSERT_THAT(siv_params, NotNull());
+ EXPECT_THAT(siv_params->GetVariant(), Eq(test_case.variant));
+ EXPECT_THAT(siv_params->KeySizeInBytes(), Eq(test_case.key_size));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseParametersWithInvalidSerialization) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ AesSivKeyFormat key_format_proto;
+ key_format_proto.set_version(0);
+ key_format_proto.set_key_size(64);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey",
+ OutputPrefixType::RAW, "invalid_serialization");
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseParametersWithUnkownOutputPrefix) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ AesSivKeyFormat key_format_proto;
+ key_format_proto.set_version(0);
+ key_format_proto.set_key_size(64);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey",
+ OutputPrefixType::UNKNOWN_PREFIX,
+ key_format_proto.SerializeAsString());
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseParametersWithInvalidVersion) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ AesSivKeyFormat key_format_proto;
+ key_format_proto.set_version(1);
+ key_format_proto.set_key_size(64);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey",
+ OutputPrefixType::RAW, key_format_proto.SerializeAsString());
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_P(AesSivProtoSerializationTest, SerializeParameters) {
+ TestCase test_case = GetParam();
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ util::StatusOr<AesSivParameters> parameters =
+ AesSivParameters::Create(test_case.key_size, test_case.variant);
+ ASSERT_THAT(parameters, IsOk());
+
+ util::StatusOr<std::unique_ptr<Serialization>> serialization =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .SerializeParameters<internal::ProtoParametersSerialization>(
+ *parameters);
+ ASSERT_THAT(serialization, IsOk());
+ EXPECT_THAT((*serialization)->ObjectIdentifier(),
+ Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
+
+ const internal::ProtoParametersSerialization* proto_serialization =
+ dynamic_cast<const internal::ProtoParametersSerialization*>(
+ serialization->get());
+ ASSERT_THAT(proto_serialization, NotNull());
+ EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
+ Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
+ EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
+ Eq(test_case.output_prefix_type));
+
+ AesSivKeyFormat key_format;
+ ASSERT_THAT(
+ key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
+ IsTrue());
+ EXPECT_THAT(key_format.key_size(), Eq(test_case.key_size));
+}
+
+TEST_P(AesSivProtoSerializationTest, ParseKey) {
+ TestCase test_case = GetParam();
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
+ google::crypto::tink::AesSivKey key_proto;
+ key_proto.set_version(0);
+ key_proto.set_key_value(raw_key_bytes);
+ RestrictedData serialized_key = RestrictedData(
+ key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
+
+ util::StatusOr<internal::ProtoKeySerialization> serialization =
+ internal::ProtoKeySerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
+ KeyData::SYMMETRIC, test_case.output_prefix_type, test_case.id);
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Key>> key =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
+ *serialization, InsecureSecretKeyAccess::Get());
+ ASSERT_THAT(key, IsOk());
+ EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id));
+ EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
+ test_case.id.has_value());
+
+ util::StatusOr<AesSivParameters> expected_parameters =
+ AesSivParameters::Create(test_case.key_size, test_case.variant);
+ ASSERT_THAT(expected_parameters, IsOk());
+
+ util::StatusOr<AesSivKey> expected_key = AesSivKey::Create(
+ *expected_parameters,
+ RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
+ test_case.id, GetPartialKeyAccess());
+ ASSERT_THAT(expected_key, IsOk());
+
+ EXPECT_THAT(**key, Eq(*expected_key));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseLegacyKeyAsCrunchy) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(64);
+ google::crypto::tink::AesSivKey key_proto;
+ key_proto.set_version(0);
+ key_proto.set_key_value(raw_key_bytes);
+ RestrictedData serialized_key = RestrictedData(
+ key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
+
+ util::StatusOr<internal::ProtoKeySerialization> serialization =
+ internal::ProtoKeySerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
+ KeyData::SYMMETRIC, OutputPrefixType::LEGACY, /*id_requirement=*/123);
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Key>> key =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
+ *serialization, InsecureSecretKeyAccess::Get());
+ ASSERT_THAT(key, IsOk());
+
+ const AesSivKey* aes_siv_key = dynamic_cast<const AesSivKey*>(key->get());
+ ASSERT_THAT(aes_siv_key, NotNull());
+ EXPECT_THAT(aes_siv_key->GetParameters().GetVariant(),
+ Eq(AesSivParameters::Variant::kCrunchy));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseKeyWithInvalidSerialization) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ RestrictedData serialized_key =
+ RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
+
+ util::StatusOr<internal::ProtoKeySerialization> serialization =
+ internal::ProtoKeySerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
+ KeyData::SYMMETRIC, OutputPrefixType::TINK,
+ /*id_requirement=*/0x23456789);
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Key>> key =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
+ *serialization, InsecureSecretKeyAccess::Get());
+ EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseKeyNoSecretKeyAccess) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(64);
+ google::crypto::tink::AesSivKey key_proto;
+ key_proto.set_version(0);
+ key_proto.set_key_value(raw_key_bytes);
+ RestrictedData serialized_key = RestrictedData(
+ key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
+
+ util::StatusOr<internal::ProtoKeySerialization> serialization =
+ internal::ProtoKeySerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
+ KeyData::SYMMETRIC, OutputPrefixType::TINK,
+ /*id_requirement=*/0x23456789);
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Key>> key =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
+ *serialization, /*token=*/absl::nullopt);
+ EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AesSivProtoSerializationTest, ParseKeyWithInvalidVersion) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(64);
+ google::crypto::tink::AesSivKey key_proto;
+ key_proto.set_version(1); // Invalid version number.
+ key_proto.set_key_value(raw_key_bytes);
+ RestrictedData serialized_key = RestrictedData(
+ key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
+
+ util::StatusOr<internal::ProtoKeySerialization> serialization =
+ internal::ProtoKeySerialization::Create(
+ "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
+ KeyData::SYMMETRIC, OutputPrefixType::TINK,
+ /*id_requirement=*/0x23456789);
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Key>> key =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
+ *serialization, InsecureSecretKeyAccess::Get());
+ EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_P(AesSivProtoSerializationTest, SerializeKey) {
+ TestCase test_case = GetParam();
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ util::StatusOr<AesSivParameters> parameters =
+ AesSivParameters::Create(test_case.key_size, test_case.variant);
+ ASSERT_THAT(parameters, IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
+ util::StatusOr<AesSivKey> key = AesSivKey::Create(
+ *parameters,
+ RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
+ test_case.id, GetPartialKeyAccess());
+ ASSERT_THAT(key, IsOk());
+
+ util::StatusOr<std::unique_ptr<Serialization>> serialization =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .SerializeKey<internal::ProtoKeySerialization>(
+ *key, InsecureSecretKeyAccess::Get());
+ ASSERT_THAT(serialization, IsOk());
+ EXPECT_THAT((*serialization)->ObjectIdentifier(),
+ Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
+
+ const internal::ProtoKeySerialization* proto_serialization =
+ dynamic_cast<const internal::ProtoKeySerialization*>(
+ serialization->get());
+ ASSERT_THAT(proto_serialization, NotNull());
+ EXPECT_THAT(proto_serialization->TypeUrl(),
+ Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
+ EXPECT_THAT(proto_serialization->KeyMaterialType(), Eq(KeyData::SYMMETRIC));
+ EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
+ Eq(test_case.output_prefix_type));
+ EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
+
+ google::crypto::tink::AesSivKey proto_key;
+ // OSS proto library complains if input is not converted to a string.
+ ASSERT_THAT(proto_key.ParseFromString(std::string(
+ proto_serialization->SerializedKeyProto().GetSecret(
+ InsecureSecretKeyAccess::Get()))),
+ IsTrue());
+ EXPECT_THAT(proto_key.key_value().size(), Eq(test_case.key_size));
+}
+
+TEST_F(AesSivProtoSerializationTest, SerializeKeyNoSecretKeyAccess) {
+ ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
+
+ util::StatusOr<AesSivParameters> parameters = AesSivParameters::Create(
+ /*key_size_in_bytes=*/64, AesSivParameters::Variant::kNoPrefix);
+ ASSERT_THAT(parameters, IsOk());
+
+ std::string raw_key_bytes = Random::GetRandomBytes(64);
+ util::StatusOr<AesSivKey> key = AesSivKey::Create(
+ *parameters,
+ RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
+ /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
+ ASSERT_THAT(key, IsOk());
+
+ util::StatusOr<std::unique_ptr<Serialization>> serialization =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .SerializeKey<internal::ProtoKeySerialization>(*key, absl::nullopt);
+ EXPECT_THAT(serialization.status(),
+ StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto