xref: /aosp_15_r20/external/tink/cc/mac/hmac_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/mac/hmac_proto_serialization.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "tink/insecure_secret_key_access.h"
25 #include "tink/internal/mutable_serialization_registry.h"
26 #include "tink/internal/proto_key_serialization.h"
27 #include "tink/internal/proto_parameters_serialization.h"
28 #include "tink/mac/hmac_key.h"
29 #include "tink/mac/hmac_parameters.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/common.pb.h"
35 #include "proto/hmac.pb.h"
36 #include "proto/tink.pb.h"
37 
38 namespace crypto {
39 namespace tink {
40 namespace {
41 
42 using ::crypto::tink::subtle::Random;
43 using ::crypto::tink::test::IsOk;
44 using ::crypto::tink::test::IsOkAndHolds;
45 using ::crypto::tink::test::StatusIs;
46 using ::google::crypto::tink::HashType;
47 using ::google::crypto::tink::HmacKeyFormat;
48 using ::google::crypto::tink::KeyData;
49 using ::google::crypto::tink::OutputPrefixType;
50 using ::testing::Eq;
51 using ::testing::IsTrue;
52 using ::testing::NotNull;
53 using ::testing::TestWithParam;
54 using ::testing::Values;
55 
56 struct TestCase {
57   HmacParameters::Variant variant;
58   OutputPrefixType output_prefix_type;
59   HmacParameters::HashType hash_type;
60   HashType proto_hash_type;
61   int key_size;
62   int tag_size;
63   int total_size;
64   absl::optional<int> id;
65   std::string output_prefix;
66 };
67 
68 class HmacProtoSerializationTest : public TestWithParam<TestCase> {
69  protected:
SetUp()70   void SetUp() override {
71     internal::MutableSerializationRegistry::GlobalInstance().Reset();
72   }
73 };
74 
75 INSTANTIATE_TEST_SUITE_P(
76     HmacProtoSerializationTestSuite, HmacProtoSerializationTest,
77     Values(TestCase{HmacParameters::Variant::kTink, OutputPrefixType::TINK,
78                     HmacParameters::HashType::kSha1, HashType::SHA1,
79                     /*key_size=*/16, /*cryptographic_tag_size=*/10,
80                     /*total_size=*/15, /*id=*/0x02030400,
81                     /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
82            TestCase{HmacParameters::Variant::kCrunchy,
83                     OutputPrefixType::CRUNCHY,
84                     HmacParameters::HashType::kSha224, HashType::SHA224,
85                     /*key_size=*/16, /*tag_size=*/12, /*total_size=*/17,
86                     /*id=*/0x01030005,
87                     /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
88            TestCase{HmacParameters::Variant::kLegacy, OutputPrefixType::LEGACY,
89                     HmacParameters::HashType::kSha256, HashType::SHA256,
90                     /*key_size=*/32, /*cryptographic_tag_size=*/14,
91                     /*total_tag_size=*/19, /*id=*/0x01020304,
92                     /*output_prefix=*/std::string("\x00\x01\x02\x03\x04", 5)},
93            TestCase{HmacParameters::Variant::kNoPrefix, OutputPrefixType::RAW,
94                     HmacParameters::HashType::kSha384, HashType::SHA384,
95                     /*key_size=*/32, /*cryptographic_tag_size=*/16,
96                     /*total_tag_size=*/16, /*id=*/absl::nullopt,
97                     /*output_prefix=*/""},
98            TestCase{HmacParameters::Variant::kNoPrefix, OutputPrefixType::RAW,
99                     HmacParameters::HashType::kSha512, HashType::SHA512,
100                     /*key_size=*/32, /*cryptographic_tag_size=*/20,
101                     /*total_tag_size=*/20, /*id=*/absl::nullopt,
102                     /*output_prefix=*/""}));
103 
TEST_P(HmacProtoSerializationTest,ParseParameters)104 TEST_P(HmacProtoSerializationTest, ParseParameters) {
105   TestCase test_case = GetParam();
106   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
107 
108   HmacKeyFormat key_format_proto;
109   key_format_proto.set_key_size(test_case.key_size);
110   key_format_proto.mutable_params()->set_tag_size(test_case.tag_size);
111   key_format_proto.mutable_params()->set_hash(test_case.proto_hash_type);
112 
113   util::StatusOr<internal::ProtoParametersSerialization> serialization =
114       internal::ProtoParametersSerialization::Create(
115           "type.googleapis.com/google.crypto.tink.HmacKey",
116           test_case.output_prefix_type, key_format_proto.SerializeAsString());
117   ASSERT_THAT(serialization, IsOk());
118 
119   util::StatusOr<std::unique_ptr<Parameters>> parsed_parameters =
120       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
121           *serialization);
122   ASSERT_THAT(parsed_parameters, IsOk());
123   EXPECT_THAT((*parsed_parameters)->HasIdRequirement(),
124               test_case.id.has_value());
125 
126   util::StatusOr<HmacParameters> expected_parameters =
127       HmacParameters::Create(test_case.key_size, test_case.tag_size,
128                              test_case.hash_type, test_case.variant);
129   ASSERT_THAT(expected_parameters, IsOk());
130   ASSERT_THAT(**parsed_parameters, Eq(*expected_parameters));
131 }
132 
TEST_F(HmacProtoSerializationTest,ParseParametersWithInvalidSerialization)133 TEST_F(HmacProtoSerializationTest, ParseParametersWithInvalidSerialization) {
134   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
135 
136   util::StatusOr<internal::ProtoParametersSerialization> serialization =
137       internal::ProtoParametersSerialization::Create(
138           "type.googleapis.com/google.crypto.tink.HmacKey",
139           OutputPrefixType::RAW, "invalid_serialization");
140   ASSERT_THAT(serialization, IsOk());
141 
142   util::StatusOr<std::unique_ptr<Parameters>> params =
143       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
144           *serialization);
145   ASSERT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
146 }
147 
TEST_F(HmacProtoSerializationTest,ParseParametersWithInvalidVersion)148 TEST_F(HmacProtoSerializationTest, ParseParametersWithInvalidVersion) {
149   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
150 
151   HmacKeyFormat key_format_proto;
152   key_format_proto.set_key_size(16);
153   key_format_proto.set_version(1);  // Invalid version.
154   key_format_proto.mutable_params()->set_tag_size(10);
155   key_format_proto.mutable_params()->set_hash(HashType::SHA256);
156 
157   util::StatusOr<internal::ProtoParametersSerialization> serialization =
158       internal::ProtoParametersSerialization::Create(
159           "type.googleapis.com/google.crypto.tink.HmacKey",
160           OutputPrefixType::RAW, key_format_proto.SerializeAsString());
161   ASSERT_THAT(serialization, IsOk());
162 
163   util::StatusOr<std::unique_ptr<Parameters>> params =
164       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
165           *serialization);
166   ASSERT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
167 }
168 
TEST_F(HmacProtoSerializationTest,ParseParametersWithUnkownOutputPrefix)169 TEST_F(HmacProtoSerializationTest, ParseParametersWithUnkownOutputPrefix) {
170   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
171 
172   HmacKeyFormat key_format_proto;
173   key_format_proto.set_key_size(16);
174   key_format_proto.mutable_params()->set_tag_size(10);
175 
176   util::StatusOr<internal::ProtoParametersSerialization> serialization =
177       internal::ProtoParametersSerialization::Create(
178           "type.googleapis.com/google.crypto.tink.HmacKey",
179           OutputPrefixType::UNKNOWN_PREFIX,
180           key_format_proto.SerializeAsString());
181   ASSERT_THAT(serialization, IsOk());
182 
183   util::StatusOr<std::unique_ptr<Parameters>> params =
184       internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
185           *serialization);
186   ASSERT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
187 }
188 
TEST_P(HmacProtoSerializationTest,SerializeParameters)189 TEST_P(HmacProtoSerializationTest, SerializeParameters) {
190   TestCase test_case = GetParam();
191   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
192 
193   util::StatusOr<HmacParameters> parameters =
194       HmacParameters::Create(test_case.key_size, test_case.tag_size,
195                              test_case.hash_type, test_case.variant);
196   ASSERT_THAT(parameters, IsOk());
197 
198   util::StatusOr<std::unique_ptr<Serialization>> serialization =
199       internal::MutableSerializationRegistry::GlobalInstance()
200           .SerializeParameters<internal::ProtoParametersSerialization>(
201               *parameters);
202   ASSERT_THAT(serialization, IsOk());
203   EXPECT_THAT((*serialization)->ObjectIdentifier(),
204               Eq("type.googleapis.com/google.crypto.tink.HmacKey"));
205 
206   const internal::ProtoParametersSerialization* proto_serialization =
207       dynamic_cast<const internal::ProtoParametersSerialization*>(
208           serialization->get());
209   ASSERT_THAT(proto_serialization, NotNull());
210   EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
211               Eq("type.googleapis.com/google.crypto.tink.HmacKey"));
212   EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
213               Eq(test_case.output_prefix_type));
214 
215   HmacKeyFormat key_format;
216   ASSERT_THAT(
217       key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
218       IsTrue());
219   ASSERT_THAT(key_format.key_size(), Eq(test_case.key_size));
220   ASSERT_THAT(key_format.params().tag_size(), Eq(test_case.tag_size));
221   ASSERT_THAT(key_format.params().hash(), Eq(test_case.proto_hash_type));
222 }
223 
TEST_P(HmacProtoSerializationTest,ParseKey)224 TEST_P(HmacProtoSerializationTest, ParseKey) {
225   TestCase test_case = GetParam();
226   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
227 
228   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
229   google::crypto::tink::HmacKey key_proto;
230   key_proto.set_version(0);
231   key_proto.set_key_value(raw_key_bytes);
232   key_proto.mutable_params()->set_tag_size(test_case.tag_size);
233   key_proto.mutable_params()->set_hash(test_case.proto_hash_type);
234   RestrictedData serialized_key = RestrictedData(
235       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
236 
237   util::StatusOr<internal::ProtoKeySerialization> serialization =
238       internal::ProtoKeySerialization::Create(
239           "type.googleapis.com/google.crypto.tink.HmacKey", serialized_key,
240           KeyData::SYMMETRIC, test_case.output_prefix_type, test_case.id);
241   ASSERT_THAT(serialization, IsOk());
242 
243   util::StatusOr<std::unique_ptr<Key>> parsed_key =
244       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
245           *serialization, InsecureSecretKeyAccess::Get());
246   ASSERT_THAT(parsed_key, IsOk());
247   EXPECT_THAT((*parsed_key)->GetParameters().HasIdRequirement(),
248               test_case.id.has_value());
249   EXPECT_THAT((*parsed_key)->GetIdRequirement(), Eq(test_case.id));
250 
251   util::StatusOr<HmacParameters> expected_parameters =
252       HmacParameters::Create(test_case.key_size, test_case.tag_size,
253                              test_case.hash_type, test_case.variant);
254   ASSERT_THAT(expected_parameters, IsOk());
255   util::StatusOr<HmacKey> expected_key = HmacKey::Create(
256       *expected_parameters,
257       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
258       test_case.id, GetPartialKeyAccess());
259 
260   ASSERT_THAT(expected_key, IsOk());
261   ASSERT_THAT(**parsed_key, Eq(*expected_key));
262 }
263 
TEST_F(HmacProtoSerializationTest,ParseKeyWithInvalidSerialization)264 TEST_F(HmacProtoSerializationTest, ParseKeyWithInvalidSerialization) {
265   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
266 
267   std::string raw_key_bytes = Random::GetRandomBytes(16);
268   google::crypto::tink::HmacKey key_proto;
269   key_proto.set_version(0);
270   key_proto.set_key_value(raw_key_bytes);
271   key_proto.mutable_params()->set_tag_size(10);
272   key_proto.mutable_params()->set_hash(HashType::SHA256);
273   RestrictedData serialized_key =
274       RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
275 
276   util::StatusOr<internal::ProtoKeySerialization> serialization =
277       internal::ProtoKeySerialization::Create(
278           "type.googleapis.com/google.crypto.tink.HmacKey", serialized_key,
279           KeyData::SYMMETRIC, OutputPrefixType::TINK,
280           /*id_requirement=*/0x23456789);
281   ASSERT_THAT(serialization, IsOk());
282 
283   util::StatusOr<std::unique_ptr<Key>> key =
284       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
285           *serialization, InsecureSecretKeyAccess::Get());
286   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
287 }
288 
TEST_F(HmacProtoSerializationTest,ParseKeyWithInvalidVersion)289 TEST_F(HmacProtoSerializationTest, ParseKeyWithInvalidVersion) {
290   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
291 
292   std::string raw_key_bytes = Random::GetRandomBytes(16);
293   google::crypto::tink::HmacKey key_proto;
294   key_proto.set_version(1);  // Invalid version number.
295   key_proto.set_key_value(raw_key_bytes);
296   key_proto.mutable_params()->set_tag_size(10);
297   key_proto.mutable_params()->set_hash(HashType::SHA256);
298   RestrictedData serialized_key = RestrictedData(
299       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
300 
301   util::StatusOr<internal::ProtoKeySerialization> serialization =
302       internal::ProtoKeySerialization::Create(
303           "type.googleapis.com/google.crypto.tink.HmacKey", serialized_key,
304           KeyData::SYMMETRIC, OutputPrefixType::TINK,
305           /*id_requirement=*/0x23456789);
306   ASSERT_THAT(serialization, IsOk());
307 
308   util::StatusOr<std::unique_ptr<Key>> key =
309       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
310           *serialization, InsecureSecretKeyAccess::Get());
311   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
312 }
313 
TEST_F(HmacProtoSerializationTest,ParseKeyWithoutSecretKeyAccess)314 TEST_F(HmacProtoSerializationTest, ParseKeyWithoutSecretKeyAccess) {
315   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
316 
317   std::string raw_key_bytes = Random::GetRandomBytes(16);
318   google::crypto::tink::HmacKey key_proto;
319   key_proto.set_version(0);
320   key_proto.set_key_value(raw_key_bytes);
321   key_proto.mutable_params()->set_tag_size(10);
322   key_proto.mutable_params()->set_hash(HashType::SHA256);
323   RestrictedData serialized_key = RestrictedData(
324       key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
325 
326   util::StatusOr<internal::ProtoKeySerialization> serialization =
327       internal::ProtoKeySerialization::Create(
328           "type.googleapis.com/google.crypto.tink.HmacKey", serialized_key,
329           KeyData::SYMMETRIC, OutputPrefixType::TINK,
330           /*id_requirement=*/0x23456789);
331   ASSERT_THAT(serialization, IsOk());
332 
333   util::StatusOr<std::unique_ptr<Key>> key =
334       internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
335           *serialization, absl::nullopt);
336   ASSERT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
337 }
338 
TEST_P(HmacProtoSerializationTest,SerializeKey)339 TEST_P(HmacProtoSerializationTest, SerializeKey) {
340   TestCase test_case = GetParam();
341   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
342 
343   util::StatusOr<HmacParameters> parameters =
344       HmacParameters::Create(test_case.key_size, test_case.tag_size,
345                              test_case.hash_type, test_case.variant);
346   ASSERT_THAT(parameters, IsOk());
347 
348   std::string raw_key_bytes = Random::GetRandomBytes(test_case.key_size);
349   util::StatusOr<HmacKey> key = HmacKey::Create(
350       *parameters,
351       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
352       test_case.id, GetPartialKeyAccess());
353   ASSERT_THAT(key, IsOk());
354 
355   util::StatusOr<std::unique_ptr<Serialization>> serialization =
356       internal::MutableSerializationRegistry::GlobalInstance()
357           .SerializeKey<internal::ProtoKeySerialization>(
358               *key, InsecureSecretKeyAccess::Get());
359   ASSERT_THAT(serialization, IsOk());
360   EXPECT_THAT((*serialization)->ObjectIdentifier(),
361               Eq("type.googleapis.com/google.crypto.tink.HmacKey"));
362 
363   const internal::ProtoKeySerialization* proto_serialization =
364       dynamic_cast<const internal::ProtoKeySerialization*>(
365           serialization->get());
366   ASSERT_THAT(proto_serialization, NotNull());
367   EXPECT_THAT(proto_serialization->TypeUrl(),
368               Eq("type.googleapis.com/google.crypto.tink.HmacKey"));
369   EXPECT_THAT(proto_serialization->KeyMaterialType(), Eq(KeyData::SYMMETRIC));
370   EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
371               Eq(test_case.output_prefix_type));
372   EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
373 
374   google::crypto::tink::HmacKey proto_key;
375   // OSS proto library complains if input is not converted to a string.
376   ASSERT_THAT(proto_key.ParseFromString(std::string(
377                   proto_serialization->SerializedKeyProto().GetSecret(
378                       InsecureSecretKeyAccess::Get()))),
379               IsTrue());
380   EXPECT_THAT(proto_key.key_value().size(), Eq(test_case.key_size));
381   EXPECT_THAT(proto_key.params().tag_size(), Eq(test_case.tag_size));
382   EXPECT_THAT(proto_key.params().hash(), Eq(test_case.proto_hash_type));
383 }
384 
TEST_F(HmacProtoSerializationTest,SerializeKeyWithoutSecretKeyAccess)385 TEST_F(HmacProtoSerializationTest, SerializeKeyWithoutSecretKeyAccess) {
386   ASSERT_THAT(RegisterHmacProtoSerialization(), IsOk());
387 
388   util::StatusOr<HmacParameters> parameters = HmacParameters::Create(
389       /*key_size_in_bytes=*/16, /*cryptographic_tag_size_in_bytes=*/10,
390       HmacParameters::HashType::kSha256, HmacParameters::Variant::kNoPrefix);
391   ASSERT_THAT(parameters, IsOk());
392 
393   std::string raw_key_bytes = Random::GetRandomBytes(16);
394   util::StatusOr<HmacKey> key = HmacKey::Create(
395       *parameters,
396       RestrictedData(raw_key_bytes, InsecureSecretKeyAccess::Get()),
397       /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
398   ASSERT_THAT(key, IsOk());
399 
400   util::StatusOr<std::unique_ptr<Serialization>> serialization =
401       internal::MutableSerializationRegistry::GlobalInstance()
402           .SerializeKey<internal::ProtoKeySerialization>(*key, absl::nullopt);
403   ASSERT_THAT(serialization.status(),
404               StatusIs(absl::StatusCode::kInvalidArgument));
405 }
406 
407 }  // namespace
408 }  // namespace tink
409 }  // namespace crypto
410