xref: /aosp_15_r20/external/tink/cc/mac/internal/chunked_mac_wrapper_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2022 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/internal/chunked_mac_wrapper.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/strings/str_cat.h"
26 #include "tink/chunked_mac.h"
27 #include "tink/mac/internal/chunked_mac_impl.h"
28 #include "tink/subtle/mac/stateful_mac.h"
29 #include "tink/util/status.h"
30 #include "tink/util/statusor.h"
31 #include "tink/util/test_matchers.h"
32 #include "proto/tink.pb.h"
33 
34 namespace crypto {
35 namespace tink {
36 namespace internal {
37 namespace {
38 
39 using ::crypto::tink::test::IsOk;
40 using ::crypto::tink::test::IsOkAndHolds;
41 using ::crypto::tink::test::StatusIs;
42 using ::google::crypto::tink::KeysetInfo;
43 using ::google::crypto::tink::KeyStatusType;
44 using ::google::crypto::tink::OutputPrefixType;
45 using ::testing::Values;
46 
47 class FakeStatefulMac : public subtle::StatefulMac {
48  public:
FakeStatefulMac(absl::string_view name)49   explicit FakeStatefulMac(absl::string_view name) : name_(name) {}
50 
Update(absl::string_view data)51   util::Status Update(absl::string_view data) override {
52     absl::StrAppend(&buffer_, data);
53     return util::OkStatus();
54   }
55 
Finalize()56   util::StatusOr<std::string> Finalize() override {
57     return absl::StrCat(name_, buffer_);
58   }
59 
60  private:
61   const std::string name_;
62   std::string buffer_ = "";
63 };
64 
65 class FakeStatefulMacFactory : public subtle::StatefulMacFactory {
66  public:
FakeStatefulMacFactory(absl::string_view name)67   explicit FakeStatefulMacFactory(absl::string_view name) : name_(name) {}
68 
Create() const69   util::StatusOr<std::unique_ptr<subtle::StatefulMac>> Create() const override {
70     return std::unique_ptr<subtle::StatefulMac>(
71         absl::make_unique<FakeStatefulMac>(name_));
72   }
73 
74  private:
75   std::string name_;
76 };
77 
TEST(ChunkedMacWrapperTest,WrapNullptr)78 TEST(ChunkedMacWrapperTest, WrapNullptr) {
79   EXPECT_THAT(ChunkedMacWrapper().Wrap(nullptr).status(),
80               StatusIs(absl::StatusCode::kInternal));
81 }
82 
TEST(ChunkedMacWrapperTest,WrapEmpty)83 TEST(ChunkedMacWrapperTest, WrapEmpty) {
84   std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set(
85       new PrimitiveSet<ChunkedMac>());
86   EXPECT_THAT(ChunkedMacWrapper().Wrap(std::move(mac_set)).status(),
87               StatusIs(absl::StatusCode::kInvalidArgument));
88 }
89 
CreateFakeChunkedMac(absl::string_view name)90 std::unique_ptr<ChunkedMac> CreateFakeChunkedMac(absl::string_view name) {
91   return absl::make_unique<ChunkedMacImpl>(
92       absl::make_unique<FakeStatefulMacFactory>(name));
93 }
94 
AddPrimitiveToSet(uint32_t key_id,bool set_primary,OutputPrefixType output_prefix_type,std::unique_ptr<ChunkedMac> mac,KeysetInfo & keyset_info,PrimitiveSet<ChunkedMac> & mac_set)95 util::Status AddPrimitiveToSet(uint32_t key_id, bool set_primary,
96                                OutputPrefixType output_prefix_type,
97                                std::unique_ptr<ChunkedMac> mac,
98                                KeysetInfo& keyset_info,
99                                PrimitiveSet<ChunkedMac>& mac_set) {
100   int index = keyset_info.key_info_size();
101   KeysetInfo::KeyInfo* key_info = keyset_info.add_key_info();
102   key_info->set_output_prefix_type(output_prefix_type);
103   key_info->set_key_id(key_id);
104   key_info->set_status(KeyStatusType::ENABLED);
105 
106   auto entry =
107       mac_set.AddPrimitive(std::move(mac), keyset_info.key_info(index));
108   if (!entry.ok()) {
109     return entry.status();
110   }
111   if (set_primary) {
112     util::Status set_primary_status = mac_set.set_primary(*entry);
113     if (!set_primary_status.ok()) {
114       return set_primary_status;
115     }
116   }
117   return util::OkStatus();
118 }
119 
TEST(ChunkedMacWrapperTest,ComputeMac)120 TEST(ChunkedMacWrapperTest, ComputeMac) {
121   KeysetInfo keyset_info;
122   auto mac_set = absl::make_unique<PrimitiveSet<ChunkedMac>>();
123 
124   // Add primitives to the primitive set.
125   ASSERT_THAT(
126       AddPrimitiveToSet(
127           /*key_id=*/0x12d66f, /*set_primary=*/false, OutputPrefixType::TINK,
128           CreateFakeChunkedMac("chunkedmac0:"), keyset_info, *mac_set),
129       IsOk());
130   ASSERT_THAT(
131       AddPrimitiveToSet(
132           /*key_id=*/0xb1539, /*set_primary=*/false, OutputPrefixType::LEGACY,
133           CreateFakeChunkedMac("chunkedmac1:"), keyset_info, *mac_set),
134       IsOk());
135   ASSERT_THAT(
136       AddPrimitiveToSet(
137           /*key_id=*/0x6e12af, /*set_primary=*/true, OutputPrefixType::TINK,
138           CreateFakeChunkedMac("chunkedmac2:"), keyset_info, *mac_set),
139       IsOk());
140 
141   // Wrap primitive set into a ChunkedMac.
142   util::StatusOr<std::unique_ptr<crypto::tink::ChunkedMac>> chunked_mac =
143       ChunkedMacWrapper().Wrap(std::move(mac_set));
144   ASSERT_THAT(chunked_mac.status(), IsOk());
145 
146   util::StatusOr<std::unique_ptr<ChunkedMacComputation>> computation =
147       (*chunked_mac)->CreateComputation();
148   EXPECT_THAT(computation.status(), IsOk());
149   EXPECT_THAT((*computation)->Update("inputdata"), IsOk());
150   util::StatusOr<std::string> tag = (*computation)->ComputeMac();
151   const std::string output_prefix = std::string("\x01\x00\x6e\x12\xaf", 5);
152   const std::string raw_tag = "chunkedmac2:inputdata";
153   EXPECT_THAT(tag, IsOkAndHolds(absl::StrCat(output_prefix, raw_tag)));
154 }
155 
TEST(ChunkedMacWrapperTest,VerifyMacWithUniquePrefix)156 TEST(ChunkedMacWrapperTest, VerifyMacWithUniquePrefix) {
157   KeysetInfo keyset_info;
158   auto mac_set = absl::make_unique<PrimitiveSet<ChunkedMac>>();
159 
160   // Add primitives to primitive set.
161   ASSERT_THAT(
162       AddPrimitiveToSet(
163           /*key_id=*/0x12d66f, /*set_primary=*/false, OutputPrefixType::TINK,
164           CreateFakeChunkedMac("chunkedmac0:"), keyset_info, *mac_set),
165       IsOk());
166   ASSERT_THAT(
167       AddPrimitiveToSet(
168           /*key_id=*/0xb1539, /*set_primary=*/false, OutputPrefixType::LEGACY,
169           CreateFakeChunkedMac("chunkedmac1:"), keyset_info, *mac_set),
170       IsOk());
171   ASSERT_THAT(
172       AddPrimitiveToSet(
173           /*key_id=*/0x6e12af, /*set_primary=*/true, OutputPrefixType::TINK,
174           CreateFakeChunkedMac("chunkedmac2:"), keyset_info, *mac_set),
175       IsOk());
176 
177   // Wrap primitive set into a ChunkedMac.
178   util::StatusOr<std::unique_ptr<crypto::tink::ChunkedMac>>
179       chunked_mac = ChunkedMacWrapper().Wrap(std::move(mac_set));
180   ASSERT_THAT(chunked_mac.status(), IsOk());
181 
182   const std::string output_prefix = std::string("\x01\x00\x6e\x12\xaf", 5);
183   const std::string raw_tag = "chunkedmac2:inputdata";
184   util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
185       (*chunked_mac)
186           ->CreateVerification(absl::StrCat(output_prefix, raw_tag));
187   EXPECT_THAT(verification.status(), IsOk());
188   EXPECT_THAT((*verification)->Update("inputdata"), IsOk());
189   EXPECT_THAT((*verification)->VerifyMac(), IsOk());
190 }
191 
TEST(ChunkedMacWrapperTest,VerifyMacWithDuplicatePrefix)192 TEST(ChunkedMacWrapperTest, VerifyMacWithDuplicatePrefix) {
193   KeysetInfo keyset_info;
194   auto mac_set = absl::make_unique<PrimitiveSet<ChunkedMac>>();
195 
196   // Add primitives to primitive set.
197   ASSERT_THAT(
198       AddPrimitiveToSet(
199           /*key_id=*/0x12d66f, /*set_primary=*/false, OutputPrefixType::LEGACY,
200           CreateFakeChunkedMac("chunkedmac0:"), keyset_info, *mac_set),
201       IsOk());
202   ASSERT_THAT(
203       AddPrimitiveToSet(
204           /*key_id=*/0x6e12af, /*set_primary=*/false, OutputPrefixType::TINK,
205           CreateFakeChunkedMac("chunkedmac1:"), keyset_info, *mac_set),
206       IsOk());
207   ASSERT_THAT(
208       AddPrimitiveToSet(
209           /*key_id=*/0x6e12af, /*set_primary=*/true, OutputPrefixType::TINK,
210           CreateFakeChunkedMac("chunkedmac2:"), keyset_info, *mac_set),
211       IsOk());
212 
213   // Wrap primitive set into a ChunkedMac.
214   util::StatusOr<std::unique_ptr<crypto::tink::ChunkedMac>>
215       chunked_mac = ChunkedMacWrapper().Wrap(std::move(mac_set));
216   ASSERT_THAT(chunked_mac.status(), IsOk());
217 
218   const std::string output_prefix = std::string("\x01\x00\x6e\x12\xaf", 5);
219   const std::string raw_tag = "chunkedmac1:inputdata";
220   util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
221       (*chunked_mac)
222           ->CreateVerification(absl::StrCat(output_prefix, raw_tag));
223   EXPECT_THAT(verification.status(), IsOk());
224   EXPECT_THAT((*verification)->Update("inputdata"), IsOk());
225   EXPECT_THAT((*verification)->VerifyMac(), IsOk());
226 }
227 
TEST(ChunkedMacWrapperTest,VerifyMacWithRawTagStartingWithKeyId)228 TEST(ChunkedMacWrapperTest, VerifyMacWithRawTagStartingWithKeyId) {
229   KeysetInfo keyset_info;
230   auto mac_set = absl::make_unique<PrimitiveSet<ChunkedMac>>();
231 
232   const std::string key_id0 = std::string("\x01\x00\x12\xd6\x6f", 5);
233 
234   // Add primitives to primitive set.
235   ASSERT_THAT(
236       AddPrimitiveToSet(
237           /*key_id=*/0x12d66f, /*set_primary=*/false, OutputPrefixType::TINK,
238           CreateFakeChunkedMac("chunkedmac0:"), keyset_info, *mac_set),
239       IsOk());
240   ASSERT_THAT(
241       AddPrimitiveToSet(
242           /*key_id=*/0x6e12af, /*set_primary=*/true, OutputPrefixType::RAW,
243           CreateFakeChunkedMac(/*name=*/absl::StrCat(key_id0, ":chunkedmac1:")),
244           keyset_info, *mac_set),
245       IsOk());
246 
247   // Wrap primitive set into a ChunkedMac.
248   util::StatusOr<std::unique_ptr<crypto::tink::ChunkedMac>>
249       chunked_mac = ChunkedMacWrapper().Wrap(std::move(mac_set));
250   ASSERT_THAT(chunked_mac.status(), IsOk());
251 
252   const std::string raw_tag = absl::StrCat(key_id0, ":chunkedmac1:inputdata");
253   util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
254       (*chunked_mac)->CreateVerification(raw_tag);
255   EXPECT_THAT(verification.status(), IsOk());
256   EXPECT_THAT((*verification)->Update("inputdata"), IsOk());
257   EXPECT_THAT((*verification)->VerifyMac(), IsOk());
258 }
259 
260 class ChunkedMacWrapperOutputPrefixTest
261     : public testing::TestWithParam<OutputPrefixType> {};
262 
263 INSTANTIATE_TEST_SUITE_P(
264     ChunkedMacWrapperOutputPrefixTestSuite, ChunkedMacWrapperOutputPrefixTest,
265     Values(OutputPrefixType::LEGACY, OutputPrefixType::RAW,
266            OutputPrefixType::CRUNCHY, OutputPrefixType::TINK));
267 
TEST_P(ChunkedMacWrapperOutputPrefixTest,ComputeVerifyMac)268 TEST_P(ChunkedMacWrapperOutputPrefixTest, ComputeVerifyMac) {
269   OutputPrefixType output_prefix_type = GetParam();
270 
271   KeysetInfo keyset_info;
272   auto mac_set = absl::make_unique<PrimitiveSet<ChunkedMac>>();
273 
274   // Add primitives to primitive set.
275   ASSERT_THAT(
276       AddPrimitiveToSet(
277           /*key_id=*/0x12d66f, /*set_primary=*/true, output_prefix_type,
278           CreateFakeChunkedMac("chunkedmac:"), keyset_info, *mac_set),
279       IsOk());
280 
281   // Wrap primitive set into a ChunkedMac.
282   util::StatusOr<std::unique_ptr<crypto::tink::ChunkedMac>> chunked_mac =
283       ChunkedMacWrapper().Wrap(std::move(mac_set));
284   ASSERT_THAT(chunked_mac.status(), IsOk());
285 
286   // Compute MAC via wrapper.
287   util::StatusOr<std::unique_ptr<ChunkedMacComputation>> mac_computation =
288       (*chunked_mac)->CreateComputation();
289   ASSERT_THAT(mac_computation.status(), IsOk());
290   ASSERT_THAT((*mac_computation)->Update("inputdata"), IsOk());
291   util::StatusOr<std::string> tag = (*mac_computation)->ComputeMac();
292   ASSERT_THAT(tag.status(), IsOk());
293 
294   // Verify MAC via wrapper.
295   util::StatusOr<std::unique_ptr<ChunkedMacVerification>> mac_verification =
296       (*chunked_mac)->CreateVerification(*tag);
297   ASSERT_THAT(mac_verification.status(), IsOk());
298   ASSERT_THAT((*mac_verification)->Update("inputdata"), IsOk());
299   ASSERT_THAT((*mac_verification)->VerifyMac(), IsOk());
300 }
301 
302 }  // namespace
303 }  // namespace internal
304 }  // namespace tink
305 }  // namespace crypto
306