xref: /aosp_15_r20/external/tink/cc/daead/aes_siv_proto_serialization_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/daead/aes_siv_proto_serialization.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "tink/daead/aes_siv_key.h"
25 #include "tink/daead/aes_siv_parameters.h"
26 #include "tink/insecure_secret_key_access.h"
27 #include "tink/internal/mutable_serialization_registry.h"
28 #include "tink/internal/proto_key_serialization.h"
29 #include "tink/internal/proto_parameters_serialization.h"
30 #include "tink/partial_key_access.h"
31 #include "tink/restricted_data.h"
32 #include "tink/subtle/random.h"
33 #include "tink/util/test_matchers.h"
34 #include "proto/aes_siv.pb.h"
35 #include "proto/tink.pb.h"
36 
37 namespace crypto {
38 namespace tink {
39 namespace {
40 
41 using ::crypto::tink::subtle::Random;
42 using ::crypto::tink::test::IsOk;
43 using ::crypto::tink::test::IsOkAndHolds;
44 using ::crypto::tink::test::StatusIs;
45 using ::google::crypto::tink::AesSivKeyFormat;
46 using ::google::crypto::tink::KeyData;
47 using ::google::crypto::tink::OutputPrefixType;
48 using ::testing::Eq;
49 using ::testing::IsTrue;
50 using ::testing::NotNull;
51 using ::testing::TestWithParam;
52 using ::testing::Values;
53 
54 struct TestCase {
55   AesSivParameters::Variant variant;
56   OutputPrefixType output_prefix_type;
57   int key_size;
58   absl::optional<int> id;
59   std::string output_prefix;
60 };
61 
62 class AesSivProtoSerializationTest : public TestWithParam<TestCase> {
63  protected:
SetUp()64   void SetUp() override {
65     internal::MutableSerializationRegistry::GlobalInstance().Reset();
66   }
67 };
68 
69 INSTANTIATE_TEST_SUITE_P(
70     AesSivProtoSerializationTestSuite, AesSivProtoSerializationTest,
71     Values(TestCase{AesSivParameters::Variant::kTink, OutputPrefixType::TINK,
72                     /*key_size=*/32, /*id=*/0x02030400,
73                     /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
74            TestCase{AesSivParameters::Variant::kCrunchy,
75                     OutputPrefixType::CRUNCHY, /*key_size=*/48,
76                     /*id=*/0x01030005,
77                     /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
78            TestCase{AesSivParameters::Variant::kNoPrefix, OutputPrefixType::RAW,
79                     /*key_size=*/64, /*id=*/absl::nullopt,
80                     /*output_prefix=*/""}));
81 
TEST_P(AesSivProtoSerializationTest,ParseParameters)82 TEST_P(AesSivProtoSerializationTest, ParseParameters) {
83   TestCase test_case = GetParam();
84   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
85 
86   AesSivKeyFormat key_format_proto;
87   key_format_proto.set_version(0);
88   key_format_proto.set_key_size(test_case.key_size);
89 
90   util::StatusOr<internal::ProtoParametersSerialization> serialization =
91       internal::ProtoParametersSerialization::Create(
92           "type.googleapis.com/google.crypto.tink.AesSivKey",
93           test_case.output_prefix_type, key_format_proto.SerializeAsString());
94   ASSERT_THAT(serialization, IsOk());
95 
96   util::StatusOr<std::unique_ptr<Parameters>> params =
97       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
98           *serialization);
99   ASSERT_THAT(params, IsOk());
100   EXPECT_THAT((*params)->HasIdRequirement(), test_case.id.has_value());
101 
102   const AesSivParameters* siv_params =
103       dynamic_cast<const AesSivParameters*>(params->get());
104   ASSERT_THAT(siv_params, NotNull());
105   EXPECT_THAT(siv_params->GetVariant(), Eq(test_case.variant));
106   EXPECT_THAT(siv_params->KeySizeInBytes(), Eq(test_case.key_size));
107 }
108 
TEST_F(AesSivProtoSerializationTest,ParseParametersWithInvalidSerialization)109 TEST_F(AesSivProtoSerializationTest, ParseParametersWithInvalidSerialization) {
110   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
111 
112   AesSivKeyFormat key_format_proto;
113   key_format_proto.set_version(0);
114   key_format_proto.set_key_size(64);
115 
116   util::StatusOr<internal::ProtoParametersSerialization> serialization =
117       internal::ProtoParametersSerialization::Create(
118           "type.googleapis.com/google.crypto.tink.AesSivKey",
119           OutputPrefixType::RAW, "invalid_serialization");
120   ASSERT_THAT(serialization, IsOk());
121 
122   util::StatusOr<std::unique_ptr<Parameters>> params =
123       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
124           *serialization);
125   EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
126 }
127 
TEST_F(AesSivProtoSerializationTest,ParseParametersWithUnkownOutputPrefix)128 TEST_F(AesSivProtoSerializationTest, ParseParametersWithUnkownOutputPrefix) {
129   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
130 
131   AesSivKeyFormat key_format_proto;
132   key_format_proto.set_version(0);
133   key_format_proto.set_key_size(64);
134 
135   util::StatusOr<internal::ProtoParametersSerialization> serialization =
136       internal::ProtoParametersSerialization::Create(
137           "type.googleapis.com/google.crypto.tink.AesSivKey",
138           OutputPrefixType::UNKNOWN_PREFIX,
139           key_format_proto.SerializeAsString());
140   ASSERT_THAT(serialization, IsOk());
141 
142   util::StatusOr<std::unique_ptr<Parameters>> params =
143       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
144           *serialization);
145   EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
146 }
147 
TEST_F(AesSivProtoSerializationTest,ParseParametersWithInvalidVersion)148 TEST_F(AesSivProtoSerializationTest, ParseParametersWithInvalidVersion) {
149   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
150 
151   AesSivKeyFormat key_format_proto;
152   key_format_proto.set_version(1);
153   key_format_proto.set_key_size(64);
154 
155   util::StatusOr<internal::ProtoParametersSerialization> serialization =
156       internal::ProtoParametersSerialization::Create(
157           "type.googleapis.com/google.crypto.tink.AesSivKey",
158           OutputPrefixType::RAW, key_format_proto.SerializeAsString());
159   ASSERT_THAT(serialization, IsOk());
160 
161   util::StatusOr<std::unique_ptr<Parameters>> params =
162       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
163           *serialization);
164   EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
165 }
166 
TEST_P(AesSivProtoSerializationTest,SerializeParameters)167 TEST_P(AesSivProtoSerializationTest, SerializeParameters) {
168   TestCase test_case = GetParam();
169   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
170 
171   util::StatusOr<AesSivParameters> parameters =
172       AesSivParameters::Create(test_case.key_size, test_case.variant);
173   ASSERT_THAT(parameters, IsOk());
174 
175   util::StatusOr<std::unique_ptr<Serialization>> serialization =
176       internal::MutableSerializationRegistry::GlobalInstance()
177           .SerializeParameters<internal::ProtoParametersSerialization>(
178               *parameters);
179   ASSERT_THAT(serialization, IsOk());
180   EXPECT_THAT((*serialization)->ObjectIdentifier(),
181               Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
182 
183   const internal::ProtoParametersSerialization* proto_serialization =
184       dynamic_cast<const internal::ProtoParametersSerialization*>(
185           serialization->get());
186   ASSERT_THAT(proto_serialization, NotNull());
187   EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
188               Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
189   EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
190               Eq(test_case.output_prefix_type));
191 
192   AesSivKeyFormat key_format;
193   ASSERT_THAT(
194       key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
195       IsTrue());
196   EXPECT_THAT(key_format.key_size(), Eq(test_case.key_size));
197 }
198 
TEST_P(AesSivProtoSerializationTest,ParseKey)199 TEST_P(AesSivProtoSerializationTest, ParseKey) {
200   TestCase test_case = GetParam();
201   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
202 
203   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
204   google::crypto::tink::AesSivKey key_proto;
205   key_proto.set_version(0);
206   key_proto.set_key_value(raw_key_bytes);
207   RestrictedData serialized_key = RestrictedData(
208       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
209 
210   util::StatusOr<internal::ProtoKeySerialization> serialization =
211       internal::ProtoKeySerialization::Create(
212           "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
213           KeyData::SYMMETRIC, test_case.output_prefix_type, test_case.id);
214   ASSERT_THAT(serialization, IsOk());
215 
216   util::StatusOr<std::unique_ptr<Key>> key =
217       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
218           *serialization, InsecureSecretKeyAccess::Get());
219   ASSERT_THAT(key, IsOk());
220   EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id));
221   EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
222               test_case.id.has_value());
223 
224   util::StatusOr<AesSivParameters> expected_parameters =
225       AesSivParameters::Create(test_case.key_size, test_case.variant);
226   ASSERT_THAT(expected_parameters, IsOk());
227 
228   util::StatusOr<AesSivKey> expected_key = AesSivKey::Create(
229       *expected_parameters,
230       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
231       test_case.id, GetPartialKeyAccess());
232   ASSERT_THAT(expected_key, IsOk());
233 
234   EXPECT_THAT(**key, Eq(*expected_key));
235 }
236 
TEST_F(AesSivProtoSerializationTest,ParseLegacyKeyAsCrunchy)237 TEST_F(AesSivProtoSerializationTest, ParseLegacyKeyAsCrunchy) {
238   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
239 
240   std::string raw_key_bytes = Random::GetRandomBytes(64);
241   google::crypto::tink::AesSivKey key_proto;
242   key_proto.set_version(0);
243   key_proto.set_key_value(raw_key_bytes);
244   RestrictedData serialized_key = RestrictedData(
245       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
246 
247   util::StatusOr<internal::ProtoKeySerialization> serialization =
248       internal::ProtoKeySerialization::Create(
249           "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
250           KeyData::SYMMETRIC, OutputPrefixType::LEGACY, /*id_requirement=*/123);
251   ASSERT_THAT(serialization, IsOk());
252 
253   util::StatusOr<std::unique_ptr<Key>> key =
254       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
255           *serialization, InsecureSecretKeyAccess::Get());
256   ASSERT_THAT(key, IsOk());
257 
258   const AesSivKey* aes_siv_key = dynamic_cast<const AesSivKey*>(key->get());
259   ASSERT_THAT(aes_siv_key, NotNull());
260   EXPECT_THAT(aes_siv_key->GetParameters().GetVariant(),
261               Eq(AesSivParameters::Variant::kCrunchy));
262 }
263 
TEST_F(AesSivProtoSerializationTest,ParseKeyWithInvalidSerialization)264 TEST_F(AesSivProtoSerializationTest, ParseKeyWithInvalidSerialization) {
265   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
266 
267   RestrictedData serialized_key =
268       RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
269 
270   util::StatusOr<internal::ProtoKeySerialization> serialization =
271       internal::ProtoKeySerialization::Create(
272           "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
273           KeyData::SYMMETRIC, OutputPrefixType::TINK,
274           /*id_requirement=*/0x23456789);
275   ASSERT_THAT(serialization, IsOk());
276 
277   util::StatusOr<std::unique_ptr<Key>> key =
278       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
279           *serialization, InsecureSecretKeyAccess::Get());
280   EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
281 }
282 
TEST_F(AesSivProtoSerializationTest,ParseKeyNoSecretKeyAccess)283 TEST_F(AesSivProtoSerializationTest, ParseKeyNoSecretKeyAccess) {
284   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
285 
286   std::string raw_key_bytes = Random::GetRandomBytes(64);
287   google::crypto::tink::AesSivKey key_proto;
288   key_proto.set_version(0);
289   key_proto.set_key_value(raw_key_bytes);
290   RestrictedData serialized_key = RestrictedData(
291       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
292 
293   util::StatusOr<internal::ProtoKeySerialization> serialization =
294       internal::ProtoKeySerialization::Create(
295           "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
296           KeyData::SYMMETRIC, OutputPrefixType::TINK,
297           /*id_requirement=*/0x23456789);
298   ASSERT_THAT(serialization, IsOk());
299 
300   util::StatusOr<std::unique_ptr<Key>> key =
301       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
302           *serialization, /*token=*/absl::nullopt);
303   EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
304 }
305 
TEST_F(AesSivProtoSerializationTest,ParseKeyWithInvalidVersion)306 TEST_F(AesSivProtoSerializationTest, ParseKeyWithInvalidVersion) {
307   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
308 
309   std::string raw_key_bytes = Random::GetRandomBytes(64);
310   google::crypto::tink::AesSivKey key_proto;
311   key_proto.set_version(1);  // Invalid version number.
312   key_proto.set_key_value(raw_key_bytes);
313   RestrictedData serialized_key = RestrictedData(
314       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
315 
316   util::StatusOr<internal::ProtoKeySerialization> serialization =
317       internal::ProtoKeySerialization::Create(
318           "type.googleapis.com/google.crypto.tink.AesSivKey", serialized_key,
319           KeyData::SYMMETRIC, OutputPrefixType::TINK,
320           /*id_requirement=*/0x23456789);
321   ASSERT_THAT(serialization, IsOk());
322 
323   util::StatusOr<std::unique_ptr<Key>> key =
324       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
325           *serialization, InsecureSecretKeyAccess::Get());
326   EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
327 }
328 
TEST_P(AesSivProtoSerializationTest,SerializeKey)329 TEST_P(AesSivProtoSerializationTest, SerializeKey) {
330   TestCase test_case = GetParam();
331   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
332 
333   util::StatusOr<AesSivParameters> parameters =
334       AesSivParameters::Create(test_case.key_size, test_case.variant);
335   ASSERT_THAT(parameters, IsOk());
336 
337   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
338   util::StatusOr<AesSivKey> key = AesSivKey::Create(
339       *parameters,
340       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
341       test_case.id, GetPartialKeyAccess());
342   ASSERT_THAT(key, IsOk());
343 
344   util::StatusOr<std::unique_ptr<Serialization>> serialization =
345       internal::MutableSerializationRegistry::GlobalInstance()
346           .SerializeKey<internal::ProtoKeySerialization>(
347               *key, InsecureSecretKeyAccess::Get());
348   ASSERT_THAT(serialization, IsOk());
349   EXPECT_THAT((*serialization)->ObjectIdentifier(),
350               Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
351 
352   const internal::ProtoKeySerialization* proto_serialization =
353       dynamic_cast<const internal::ProtoKeySerialization*>(
354           serialization->get());
355   ASSERT_THAT(proto_serialization, NotNull());
356   EXPECT_THAT(proto_serialization->TypeUrl(),
357               Eq("type.googleapis.com/google.crypto.tink.AesSivKey"));
358   EXPECT_THAT(proto_serialization->KeyMaterialType(), Eq(KeyData::SYMMETRIC));
359   EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
360               Eq(test_case.output_prefix_type));
361   EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
362 
363   google::crypto::tink::AesSivKey proto_key;
364   // OSS proto library complains if input is not converted to a string.
365   ASSERT_THAT(proto_key.ParseFromString(std::string(
366                   proto_serialization->SerializedKeyProto().GetSecret(
367                       InsecureSecretKeyAccess::Get()))),
368               IsTrue());
369   EXPECT_THAT(proto_key.key_value().size(), Eq(test_case.key_size));
370 }
371 
TEST_F(AesSivProtoSerializationTest,SerializeKeyNoSecretKeyAccess)372 TEST_F(AesSivProtoSerializationTest, SerializeKeyNoSecretKeyAccess) {
373   ASSERT_THAT(RegisterAesSivProtoSerialization(), IsOk());
374 
375   util::StatusOr<AesSivParameters> parameters = AesSivParameters::Create(
376       /*key_size_in_bytes=*/64, AesSivParameters::Variant::kNoPrefix);
377   ASSERT_THAT(parameters, IsOk());
378 
379   std::string raw_key_bytes = Random::GetRandomBytes(64);
380   util::StatusOr<AesSivKey> key = AesSivKey::Create(
381       *parameters,
382       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
383       /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
384   ASSERT_THAT(key, IsOk());
385 
386   util::StatusOr<std::unique_ptr<Serialization>> serialization =
387       internal::MutableSerializationRegistry::GlobalInstance()
388           .SerializeKey<internal::ProtoKeySerialization>(*key, absl::nullopt);
389   EXPECT_THAT(serialization.status(),
390               StatusIs(absl::StatusCode::kInvalidArgument));
391 }
392 
393 }  // namespace
394 }  // namespace tink
395 }  // namespace crypto
396