xref: /aosp_15_r20/external/tink/cc/daead/deterministic_aead_wrapper_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
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/deterministic_aead_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/status/status.h"
26 #include "tink/daead/failing_daead.h"
27 #include "tink/deterministic_aead.h"
28 #include "tink/internal/registry_impl.h"
29 #include "tink/monitoring/monitoring.h"
30 #include "tink/monitoring/monitoring_client_mocks.h"
31 #include "tink/primitive_set.h"
32 #include "tink/util/status.h"
33 #include "tink/util/test_matchers.h"
34 #include "tink/util/test_util.h"
35 
36 using ::crypto::tink::test::DummyDeterministicAead;
37 using ::crypto::tink::test::IsOk;
38 using ::crypto::tink::test::IsOkAndHolds;
39 using ::crypto::tink::test::StatusIs;
40 using ::google::crypto::tink::KeysetInfo;
41 using ::google::crypto::tink::KeyStatusType;
42 using ::google::crypto::tink::OutputPrefixType;
43 using ::testing::_;
44 using ::testing::ByMove;
45 using ::testing::IsNull;
46 using ::testing::NiceMock;
47 using ::testing::Not;
48 using ::testing::NotNull;
49 using ::testing::Return;
50 using ::testing::Test;
51 
52 namespace crypto {
53 namespace tink {
54 namespace {
55 
56 class DeterministicAeadSetWrapperTest : public ::testing::Test {
57  protected:
SetUp()58   void SetUp() override {
59   }
TearDown()60   void TearDown() override {
61   }
62 };
63 
TEST_F(DeterministicAeadSetWrapperTest,testBasic)64 TEST_F(DeterministicAeadSetWrapperTest, testBasic) {
65   {  // daead_set is nullptr.
66     auto daead_result =
67         DeterministicAeadWrapper().Wrap(nullptr);
68     EXPECT_FALSE(daead_result.ok());
69     EXPECT_EQ(absl::StatusCode::kInternal, daead_result.status().code());
70     EXPECT_PRED_FORMAT2(testing::IsSubstring, "non-NULL",
71                         std::string(daead_result.status().message()));
72   }
73 
74   {  // daead_set has no primary primitive.
75     std::unique_ptr<PrimitiveSet<DeterministicAead>> daead_set(
76         new PrimitiveSet<DeterministicAead>());
77     auto daead_result =
78         DeterministicAeadWrapper().Wrap(std::move(daead_set));
79     EXPECT_FALSE(daead_result.ok());
80     EXPECT_EQ(absl::StatusCode::kInvalidArgument,
81               daead_result.status().code());
82     EXPECT_PRED_FORMAT2(testing::IsSubstring, "no primary",
83                         std::string(daead_result.status().message()));
84   }
85 
86   {  // Correct daead_set;
87     KeysetInfo::KeyInfo* key_info;
88     KeysetInfo keyset_info;
89 
90     uint32_t key_id_0 = 1234543;
91     key_info = keyset_info.add_key_info();
92     key_info->set_output_prefix_type(OutputPrefixType::TINK);
93     key_info->set_key_id(key_id_0);
94     key_info->set_status(KeyStatusType::ENABLED);
95 
96     uint32_t key_id_1 = 726329;
97     key_info = keyset_info.add_key_info();
98     key_info->set_output_prefix_type(OutputPrefixType::LEGACY);
99     key_info->set_key_id(key_id_1);
100     key_info->set_status(KeyStatusType::ENABLED);
101 
102     uint32_t key_id_2 = 7213743;
103     key_info = keyset_info.add_key_info();
104     key_info->set_output_prefix_type(OutputPrefixType::TINK);
105     key_info->set_key_id(key_id_2);
106     key_info->set_status(KeyStatusType::ENABLED);
107 
108     std::string daead_name_0 = "daead0";
109     std::string daead_name_1 = "daead1";
110     std::string daead_name_2 = "daead2";
111     std::unique_ptr<PrimitiveSet<DeterministicAead>> daead_set(
112         new PrimitiveSet<DeterministicAead>());
113     std::unique_ptr<DeterministicAead> daead(
114         new DummyDeterministicAead(daead_name_0));
115     auto entry_result =
116         daead_set->AddPrimitive(std::move(daead), keyset_info.key_info(0));
117     ASSERT_TRUE(entry_result.ok());
118     daead = absl::make_unique<DummyDeterministicAead>(daead_name_1);
119     entry_result =
120         daead_set->AddPrimitive(std::move(daead), keyset_info.key_info(1));
121     ASSERT_TRUE(entry_result.ok());
122     daead = absl::make_unique<DummyDeterministicAead>(daead_name_2);
123     entry_result =
124         daead_set->AddPrimitive(std::move(daead), keyset_info.key_info(2));
125     ASSERT_TRUE(entry_result.ok());
126     // The last key is the primary.
127     ASSERT_THAT(daead_set->set_primary(entry_result.value()), IsOk());
128 
129     // Wrap daead_set and test the resulting DeterministicAead.
130     auto daead_result =
131         DeterministicAeadWrapper().Wrap(std::move(daead_set));
132     EXPECT_TRUE(daead_result.ok()) << daead_result.status();
133     daead = std::move(daead_result.value());
134     std::string plaintext = "some_plaintext";
135     std::string associated_data = "some_associated_data";
136 
137     auto encrypt_result =
138         daead->EncryptDeterministically(plaintext, associated_data);
139     EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status();
140     std::string ciphertext = encrypt_result.value();
141     EXPECT_PRED_FORMAT2(testing::IsSubstring, daead_name_2, ciphertext);
142 
143     auto decrypt_result =
144         daead->DecryptDeterministically(ciphertext, associated_data);
145     EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status();
146     EXPECT_EQ(plaintext, decrypt_result.value());
147 
148     decrypt_result =
149         daead->DecryptDeterministically("some bad ciphertext", associated_data);
150     EXPECT_FALSE(decrypt_result.ok());
151     EXPECT_EQ(absl::StatusCode::kInvalidArgument,
152               decrypt_result.status().code());
153     EXPECT_PRED_FORMAT2(testing::IsSubstring, "decryption failed",
154                         std::string(decrypt_result.status().message()));
155   }
156 }
157 
PopulateKeyInfo(uint32_t key_id,OutputPrefixType out_prefix_type,KeyStatusType status)158 KeysetInfo::KeyInfo PopulateKeyInfo(uint32_t key_id,
159                                     OutputPrefixType out_prefix_type,
160                                     KeyStatusType status) {
161   KeysetInfo::KeyInfo key_info;
162   key_info.set_output_prefix_type(out_prefix_type);
163   key_info.set_key_id(key_id);
164   key_info.set_status(status);
165   return key_info;
166 }
167 
168 // Creates a test keyset info object.
CreateTestKeysetInfo()169 KeysetInfo CreateTestKeysetInfo() {
170   KeysetInfo keyset_info;
171   *keyset_info.add_key_info() =
172       PopulateKeyInfo(/*key_id=*/1234543, OutputPrefixType::TINK,
173                       /*status=*/KeyStatusType::ENABLED);
174   *keyset_info.add_key_info() =
175       PopulateKeyInfo(/*key_id=*/726329, OutputPrefixType::LEGACY,
176                       /*status=*/KeyStatusType::ENABLED);
177   *keyset_info.add_key_info() =
178       PopulateKeyInfo(/*key_id=*/7213743, OutputPrefixType::TINK,
179                       /*status=*/KeyStatusType::ENABLED);
180   return keyset_info;
181 }
182 
183 // Tests for the monitoring behavior.
184 class DeterministicAeadSetWrapperWithMonitoringTest : public Test {
185  protected:
186   // Perform some common initialization: reset the global registry, set expected
187   // calls for the mock monitoring factory and the returned clients.
SetUp()188   void SetUp() override {
189     Registry::Reset();
190 
191     // Setup mocks for catching Monitoring calls.
192     auto monitoring_client_factory =
193         absl::make_unique<MockMonitoringClientFactory>();
194     auto encryption_monitoring_client =
195         absl::make_unique<NiceMock<MockMonitoringClient>>();
196     encryption_monitoring_client_ = encryption_monitoring_client.get();
197     auto decryption_monitoring_client =
198         absl::make_unique<NiceMock<MockMonitoringClient>>();
199     decryption_monitoring_client_ = decryption_monitoring_client.get();
200 
201     // Monitoring tests expect that the client factory will create the
202     // corresponding MockMonitoringClients.
203     EXPECT_CALL(*monitoring_client_factory, New(_))
204         .WillOnce(
205             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
206                 std::move(encryption_monitoring_client)))))
207         .WillOnce(
208             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
209                 std::move(decryption_monitoring_client)))));
210 
211     ASSERT_THAT(internal::RegistryImpl::GlobalInstance()
212                     .RegisterMonitoringClientFactory(
213                         std::move(monitoring_client_factory)),
214                 IsOk());
215     ASSERT_THAT(
216         internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory(),
217         Not(IsNull()));
218   }
219 
220   // Cleanup the registry to avoid mock leaks.
~DeterministicAeadSetWrapperWithMonitoringTest()221   ~DeterministicAeadSetWrapperWithMonitoringTest() override {
222     Registry::Reset();
223   }
224 
225   MockMonitoringClient* encryption_monitoring_client_;
226   MockMonitoringClient* decryption_monitoring_client_;
227 };
228 
229 // Test that successful encrypt operations are logged.
TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringEncryptSuccess)230 TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,
231        WrapKeysetWithMonitoringEncryptSuccess) {
232   // Create a primitive set and fill it with some entries
233   KeysetInfo keyset_info = CreateTestKeysetInfo();
234   const absl::flat_hash_map<std::string, std::string> annotations = {
235       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
236   auto daead_primitive_set =
237       absl::make_unique<PrimitiveSet<DeterministicAead>>(annotations);
238   ASSERT_THAT(
239       daead_primitive_set
240           ->AddPrimitive(absl::make_unique<DummyDeterministicAead>("daead0"),
241                          keyset_info.key_info(0))
242           , IsOk());
243   ASSERT_THAT(
244       daead_primitive_set
245           ->AddPrimitive(absl::make_unique<DummyDeterministicAead>("daead1"),
246                          keyset_info.key_info(1))
247           , IsOk());
248   // Set the last as primary.
249   util::StatusOr<PrimitiveSet<DeterministicAead>::Entry<DeterministicAead>*>
250       last = daead_primitive_set->AddPrimitive(
251           absl::make_unique<DummyDeterministicAead>("daead2"),
252           keyset_info.key_info(2));
253   ASSERT_THAT(last, IsOk());
254   ASSERT_THAT(daead_primitive_set->set_primary(*last), IsOk());
255   // Record the ID of the primary key.
256   const uint32_t primary_key_id = keyset_info.key_info(2).key_id();
257 
258   // Create a deterministic AEAD and encrypt some data.
259   util::StatusOr<std::unique_ptr<DeterministicAead>> daead =
260       DeterministicAeadWrapper().Wrap(std::move(daead_primitive_set));
261   ASSERT_THAT(daead, IsOkAndHolds(NotNull()));
262 
263   constexpr absl::string_view plaintext = "This is some plaintext!";
264   constexpr absl::string_view associated_data = "Some associated data!";
265 
266   // Check that calling EncryptDeterministically triggers a Log() call.
267   EXPECT_CALL(*encryption_monitoring_client_,
268               Log(primary_key_id, plaintext.size()));
269   util::StatusOr<std::string> ciphertext =
270       (*daead)->EncryptDeterministically(plaintext, associated_data);
271   EXPECT_THAT(ciphertext, IsOk());
272 }
273 
274 // Test that successful encrypt operations are logged.
TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringDecryptSuccess)275 TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,
276        WrapKeysetWithMonitoringDecryptSuccess) {
277   // Create a primitive set and fill it with some entries
278   KeysetInfo keyset_info = CreateTestKeysetInfo();
279   const absl::flat_hash_map<std::string, std::string> annotations = {
280       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
281   auto daead_primitive_set =
282       absl::make_unique<PrimitiveSet<DeterministicAead>>(annotations);
283   ASSERT_THAT(
284       daead_primitive_set
285           ->AddPrimitive(absl::make_unique<DummyDeterministicAead>("daead0"),
286                          keyset_info.key_info(0))
287           .status(),
288       IsOk());
289   ASSERT_THAT(
290       daead_primitive_set
291           ->AddPrimitive(absl::make_unique<DummyDeterministicAead>("daead1"),
292                          keyset_info.key_info(1))
293           .status(),
294       IsOk());
295   // Set the last as primary.
296   util::StatusOr<PrimitiveSet<DeterministicAead>::Entry<DeterministicAead>*>
297       last = daead_primitive_set->AddPrimitive(
298           absl::make_unique<DummyDeterministicAead>("daead2"),
299           keyset_info.key_info(2));
300   ASSERT_THAT(last, IsOk());
301   ASSERT_THAT(daead_primitive_set->set_primary(*last), IsOk());
302   // Record the ID of the primary key.
303   const uint32_t primary_key_id = keyset_info.key_info(2).key_id();
304 
305 
306   // Create a deterministic AEAD and encrypt/decrypt some data.
307   util::StatusOr<std::unique_ptr<DeterministicAead>> daead =
308       DeterministicAeadWrapper().Wrap(std::move(daead_primitive_set));
309   ASSERT_THAT(daead, IsOkAndHolds(NotNull()));
310 
311   constexpr absl::string_view plaintext = "This is some plaintext!";
312   constexpr absl::string_view associated_data = "Some associated data!";
313 
314 
315   // Check that calling DecryptDeterministically triggers a Log() call.
316   util::StatusOr<std::string> ciphertext =
317       (*daead)->EncryptDeterministically(plaintext, associated_data);
318   EXPECT_THAT(ciphertext, IsOk());
319 
320   // In the log expect the size of the ciphertext without the non-raw prefix.
321   EXPECT_CALL(*decryption_monitoring_client_,
322               Log(primary_key_id,
323                   ciphertext->size() - CryptoFormat::kNonRawPrefixSize));
324   EXPECT_THAT(
325       (*daead)->DecryptDeterministically(*ciphertext, associated_data).status(),
326       IsOk());
327 }
328 
TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringEncryptFailures)329 TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,
330        WrapKeysetWithMonitoringEncryptFailures) {
331   // Create a primitive set and fill it with some entries.
332   KeysetInfo keyset_info = CreateTestKeysetInfo();
333   const absl::flat_hash_map<std::string, std::string> annotations = {
334       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
335   auto daead_primitive_set =
336       absl::make_unique<PrimitiveSet<DeterministicAead>>(annotations);
337   ASSERT_THAT(daead_primitive_set
338                   ->AddPrimitive(CreateAlwaysFailingDeterministicAead("daead0"),
339                                  keyset_info.key_info(0))
340                   .status(),
341               IsOk());
342   ASSERT_THAT(daead_primitive_set
343                   ->AddPrimitive(CreateAlwaysFailingDeterministicAead("daead1"),
344                                  keyset_info.key_info(1))
345                   .status(),
346               IsOk());
347   // Set the last as primary.
348   util::StatusOr<PrimitiveSet<DeterministicAead>::Entry<DeterministicAead>*>
349       last = daead_primitive_set->AddPrimitive(
350           CreateAlwaysFailingDeterministicAead("daead2"),
351           keyset_info.key_info(2));
352   ASSERT_THAT(last, IsOk());
353   ASSERT_THAT(daead_primitive_set->set_primary(*last), IsOk());
354 
355 
356   // Create a deterministic AEAD and encrypt.
357   util::StatusOr<std::unique_ptr<DeterministicAead>> daead =
358       DeterministicAeadWrapper().Wrap(std::move(daead_primitive_set));
359   ASSERT_THAT(daead, IsOkAndHolds(NotNull()));
360 
361   constexpr absl::string_view plaintext = "This is some plaintext!";
362   constexpr absl::string_view associated_data = "Some associated data!";
363 
364 
365   // Check that calling EncryptDeterministically triggers a LogFailure() call.
366   EXPECT_CALL(*encryption_monitoring_client_, LogFailure());
367   util::StatusOr<std::string> ciphertext =
368       (*daead)->EncryptDeterministically(plaintext, associated_data);
369   EXPECT_THAT(ciphertext.status(), StatusIs(absl::StatusCode::kInternal));
370 }
371 
372 // Test that monitoring logs decryption failures correctly.
TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,WrapKeysetWithMonitoringDecryptFailures)373 TEST_F(DeterministicAeadSetWrapperWithMonitoringTest,
374        WrapKeysetWithMonitoringDecryptFailures) {
375   // Create a primitive set and fill it with some entries.
376   KeysetInfo keyset_info = CreateTestKeysetInfo();
377   const absl::flat_hash_map<std::string, std::string> annotations = {
378       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
379   auto daead_primitive_set =
380       absl::make_unique<PrimitiveSet<DeterministicAead>>(annotations);
381   ASSERT_THAT(daead_primitive_set
382                   ->AddPrimitive(CreateAlwaysFailingDeterministicAead("daead0"),
383                                  keyset_info.key_info(0))
384                   .status(),
385               IsOk());
386   ASSERT_THAT(daead_primitive_set
387                   ->AddPrimitive(CreateAlwaysFailingDeterministicAead("daead1"),
388                                  keyset_info.key_info(1))
389                   .status(),
390               IsOk());
391   // Set the last as primary.
392   util::StatusOr<PrimitiveSet<DeterministicAead>::Entry<DeterministicAead>*>
393       last = daead_primitive_set->AddPrimitive(
394           CreateAlwaysFailingDeterministicAead("daead2"),
395           keyset_info.key_info(2));
396   ASSERT_THAT(last, IsOk());
397   ASSERT_THAT(daead_primitive_set->set_primary(*last), IsOk());
398 
399 
400   // Create a deterministic AEAD and decrypt.
401   util::StatusOr<std::unique_ptr<DeterministicAead>> daead =
402       DeterministicAeadWrapper().Wrap(std::move(daead_primitive_set));
403   ASSERT_THAT(daead, IsOkAndHolds(NotNull()));
404 
405   constexpr absl::string_view associated_data = "Some associated data!";
406   constexpr absl::string_view ciphertext = "This is some ciphertext!";
407 
408 
409   // Check that calling DecryptDeterministically triggers a LogFailure() call.
410   EXPECT_CALL(*decryption_monitoring_client_, LogFailure());
411   EXPECT_THAT(
412       (*daead)->DecryptDeterministically(ciphertext, associated_data).status(),
413       StatusIs(absl::StatusCode::kInvalidArgument));
414 }
415 
416 }  // namespace
417 }  // namespace tink
418 }  // namespace crypto
419