xref: /aosp_15_r20/external/tink/cc/aead/aead_wrapper_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2017 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/aead/aead_wrapper.h"
18 
19 #include <stdint.h>
20 
21 #include <memory>
22 #include <string>
23 #include <utility>
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/container/flat_hash_map.h"
28 #include "absl/memory/memory.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/string_view.h"
33 #include "tink/aead.h"
34 #include "tink/aead/mock_aead.h"
35 #include "tink/crypto_format.h"
36 #include "tink/internal/registry_impl.h"
37 #include "tink/monitoring/monitoring.h"
38 #include "tink/monitoring/monitoring_client_mocks.h"
39 #include "tink/primitive_set.h"
40 #include "tink/registry.h"
41 #include "tink/util/status.h"
42 #include "tink/util/statusor.h"
43 #include "tink/util/test_matchers.h"
44 #include "tink/util/test_util.h"
45 #include "proto/tink.pb.h"
46 
47 namespace crypto {
48 namespace tink {
49 namespace {
50 
51 using ::crypto::tink::test::DummyAead;
52 using ::crypto::tink::test::IsOk;
53 using ::crypto::tink::test::StatusIs;
54 using ::google::crypto::tink::KeysetInfo;
55 using ::google::crypto::tink::KeyStatusType;
56 using ::google::crypto::tink::OutputPrefixType;
57 using ::testing::_;
58 using ::testing::ByMove;
59 using ::testing::HasSubstr;
60 using ::testing::IsNull;
61 using ::testing::IsSubstring;
62 using ::testing::Not;
63 using ::testing::Return;
64 using ::testing::StrictMock;
65 using ::testing::Test;
66 
PopulateKeyInfo(KeysetInfo::KeyInfo * key_info,uint32_t key_id,OutputPrefixType out_prefix_type,KeyStatusType status)67 void PopulateKeyInfo(KeysetInfo::KeyInfo* key_info, uint32_t key_id,
68                      OutputPrefixType out_prefix_type, KeyStatusType status) {
69   key_info->set_output_prefix_type(out_prefix_type);
70   key_info->set_key_id(key_id);
71   key_info->set_status(status);
72 }
73 
74 // Creates a test keyset info object.
CreateTestKeysetInfo()75 KeysetInfo CreateTestKeysetInfo() {
76   KeysetInfo keyset_info;
77   PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/1234543,
78                   OutputPrefixType::TINK,
79                   /*status=*/KeyStatusType::ENABLED);
80   PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/726329,
81                   OutputPrefixType::LEGACY,
82                   /*status=*/KeyStatusType::ENABLED);
83   PopulateKeyInfo(keyset_info.add_key_info(), /*key_id=*/7213743,
84                   OutputPrefixType::TINK,
85                   /*status=*/KeyStatusType::ENABLED);
86   return keyset_info;
87 }
88 
TEST(AeadSetWrapperTest,WrapNullptr)89 TEST(AeadSetWrapperTest, WrapNullptr) {
90   AeadWrapper wrapper;
91   util::StatusOr<std::unique_ptr<Aead>> aead = wrapper.Wrap(nullptr);
92   EXPECT_THAT(aead, Not(IsOk()));
93   EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInternal));
94   EXPECT_PRED_FORMAT2(IsSubstring, "non-NULL",
95                       std::string(aead.status().message()));
96 }
97 
TEST(AeadSetWrapperTest,WrapEmpty)98 TEST(AeadSetWrapperTest, WrapEmpty) {
99   AeadWrapper wrapper;
100   util::StatusOr<std::unique_ptr<Aead>> aead =
101       wrapper.Wrap(absl::make_unique<PrimitiveSet<Aead>>());
102   EXPECT_THAT(aead, Not(IsOk()));
103   EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInvalidArgument));
104   EXPECT_PRED_FORMAT2(IsSubstring, "no primary",
105                       std::string(aead.status().message()));
106 }
107 
TEST(AeadSetWrapperTest,Basic)108 TEST(AeadSetWrapperTest, Basic) {
109   KeysetInfo keyset_info = CreateTestKeysetInfo();
110   std::string aead_name_0 = "aead0";
111   std::string aead_name_1 = "aead1";
112   std::string aead_name_2 = "aead2";
113   auto aead_set = absl::make_unique<PrimitiveSet<Aead>>();
114   std::unique_ptr<Aead> aead = absl::make_unique<DummyAead>(aead_name_0);
115   util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> aead_entry =
116       aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
117   EXPECT_THAT(aead_entry, IsOk());
118   aead = absl::make_unique<DummyAead>(aead_name_1);
119   aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(1));
120   EXPECT_THAT(aead_entry, IsOk());
121   aead = absl::make_unique<DummyAead>(aead_name_2);
122   aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(2));
123   EXPECT_THAT(aead_entry, IsOk());
124   // The last key is the primary.
125   EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
126 
127   // Wrap aead_set and test the resulting Aead.
128   AeadWrapper wrapper;
129   util::StatusOr<std::unique_ptr<Aead>> aead_result =
130       wrapper.Wrap(std::move(aead_set));
131   EXPECT_THAT(aead_result, IsOk());
132   aead = std::move(*aead_result);
133   std::string plaintext = "some_plaintext";
134   std::string aad = "some_aad";
135 
136   util::StatusOr<std::string> encrypt_result = aead->Encrypt(plaintext, aad);
137   EXPECT_THAT(encrypt_result, IsOk());
138   std::string ciphertext = *encrypt_result;
139   EXPECT_PRED_FORMAT2(testing::IsSubstring, aead_name_2, ciphertext);
140 
141   util::StatusOr<std::string> resulting_plaintext =
142       aead->Decrypt(ciphertext, aad);
143   EXPECT_THAT(resulting_plaintext, IsOk());
144   EXPECT_EQ(*resulting_plaintext, plaintext);
145 
146   resulting_plaintext = aead->Decrypt("some bad ciphertext", aad);
147   EXPECT_THAT(resulting_plaintext, Not(IsOk()));
148   EXPECT_THAT(resulting_plaintext.status(),
149               StatusIs(absl::StatusCode::kInvalidArgument));
150   EXPECT_PRED_FORMAT2(IsSubstring, "decryption failed",
151                       std::string(resulting_plaintext.status().message()));
152 }
153 
TEST(AeadSetWrapperTest,DecryptNonPrimary)154 TEST(AeadSetWrapperTest, DecryptNonPrimary) {
155   KeysetInfo keyset_info = CreateTestKeysetInfo();
156   std::string aead_name_0 = "aead0";
157   std::string aead_name_1 = "aead1";
158   std::string aead_name_2 = "aead2";
159   std::unique_ptr<PrimitiveSet<Aead>> aead_set(new PrimitiveSet<Aead>());
160   std::unique_ptr<Aead> aead = absl::make_unique<DummyAead>(aead_name_0);
161 
162   // Encrypt some message with the first aead.s
163   std::string plaintext = "some_plaintext";
164   std::string aad = "some_aad";
165   util::StatusOr<std::string> ciphertext = aead->Encrypt(plaintext, aad);
166   EXPECT_THAT(ciphertext, IsOk());
167   util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> aead_entry =
168       aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
169   ASSERT_THAT(aead_entry, IsOk());
170   EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
171 
172   // The complete ciphertext is of the form: | key_id | ciphertext |.
173   std::string complete_ciphertext =
174       absl::StrCat(aead_set->get_primary()->get_identifier(), *ciphertext);
175 
176   aead = absl::make_unique<DummyAead>(aead_name_1);
177   aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(1));
178   EXPECT_THAT(aead_entry, IsOk());
179   aead = absl::make_unique<DummyAead>(aead_name_2);
180   aead_entry = aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(2));
181   EXPECT_THAT(aead_entry, IsOk());
182   // The last key is the primary.
183   EXPECT_THAT(aead_set->set_primary(*aead_entry), IsOk());
184 
185   // Wrap aead_set and test the resulting Aead.
186   AeadWrapper wrapper;
187   util::StatusOr<std::unique_ptr<Aead>> aead_wrapped =
188       wrapper.Wrap(std::move(aead_set));
189   EXPECT_THAT(aead_wrapped, IsOk());
190   aead = std::move(*aead_wrapped);
191   EXPECT_THAT(complete_ciphertext, HasSubstr(aead_name_0));
192 
193   // Primary key is different from the one we used to encrypt. This
194   // should still be decryptable as we have the correct key in the set.
195   util::StatusOr<std::string> decrypted_plaintext =
196       aead->Decrypt(complete_ciphertext, aad);
197   EXPECT_THAT(decrypted_plaintext, IsOk());
198 }
199 
200 // Tests with monitoring enabled.
201 class AeadSetWrapperTestWithMonitoring : public Test {
202  protected:
203   // Perform some common initialization: reset the global registry, set expected
204   // calls for the mock monitoring factory and the returned clients.
SetUp()205   void SetUp() override {
206     Registry::Reset();
207     auto monitoring_client_factory =
208         absl::make_unique<MockMonitoringClientFactory>();
209 
210     auto encryption_monitoring_client =
211         absl::make_unique<StrictMock<MockMonitoringClient>>();
212     encryption_monitoring_client_ptr_ = encryption_monitoring_client.get();
213     auto decryption_monitoring_client =
214         absl::make_unique<StrictMock<MockMonitoringClient>>();
215     decryption_monitoring_client_ptr_ = decryption_monitoring_client.get();
216 
217     EXPECT_CALL(*monitoring_client_factory, New(_))
218         .WillOnce(
219             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
220                 std::move(encryption_monitoring_client)))))
221         .WillOnce(
222             Return(ByMove(util::StatusOr<std::unique_ptr<MonitoringClient>>(
223                 std::move(decryption_monitoring_client)))));
224 
225     ASSERT_THAT(internal::RegistryImpl::GlobalInstance()
226                     .RegisterMonitoringClientFactory(
227                         std::move(monitoring_client_factory)),
228                 IsOk());
229     ASSERT_THAT(
230         internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory(),
231         Not(IsNull()));
232   }
233 
234   // Cleanup the registry to avoid mock leaks.
TearDown()235   void TearDown() override { Registry::Reset(); }
236 
237   MockMonitoringClient* encryption_monitoring_client_ptr_;
238   MockMonitoringClient* decryption_monitoring_client_ptr_;
239 };
240 
241 // Test that successful encrypt/decrypt operations are logged.
TEST_F(AeadSetWrapperTestWithMonitoring,WrapKeysetWithMonitoringEncryptDecryptSuccess)242 TEST_F(AeadSetWrapperTestWithMonitoring,
243        WrapKeysetWithMonitoringEncryptDecryptSuccess) {
244   // Populate a primitive set.
245   KeysetInfo keyset_info = CreateTestKeysetInfo();
246   const absl::flat_hash_map<std::string, std::string> kAnnotations = {
247       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
248   auto aead_primitive_set = absl::make_unique<PrimitiveSet<Aead>>(kAnnotations);
249   ASSERT_THAT(aead_primitive_set
250                   ->AddPrimitive(absl::make_unique<DummyAead>("aead0"),
251                                  keyset_info.key_info(0))
252                   .status(),
253               IsOk());
254   ASSERT_THAT(aead_primitive_set
255                   ->AddPrimitive(absl::make_unique<DummyAead>("aead1"),
256                                  keyset_info.key_info(1))
257                   .status(),
258               IsOk());
259   // Set the last as primary.
260   util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> last =
261       aead_primitive_set->AddPrimitive(absl::make_unique<DummyAead>("aead2"),
262                                        keyset_info.key_info(2));
263   ASSERT_THAT(last, IsOk());
264   ASSERT_THAT(aead_primitive_set->set_primary(*last), IsOk());
265   // Record the ID of the primary key.
266   const uint32_t kPrimaryKeyId = keyset_info.key_info(2).key_id();
267 
268   util::StatusOr<std::unique_ptr<Aead>> aead =
269       AeadWrapper().Wrap(std::move(aead_primitive_set));
270   ASSERT_THAT(aead, IsOk());
271 
272   constexpr absl::string_view kPlaintext = "This is some plaintext!";
273   constexpr absl::string_view kAssociatedData = "Some associated data!";
274   EXPECT_CALL(*encryption_monitoring_client_ptr_,
275               Log(kPrimaryKeyId, kPlaintext.size()));
276   util::StatusOr<std::string> ciphertext =
277       (*aead)->Encrypt(kPlaintext, kAssociatedData);
278   ASSERT_THAT(ciphertext, IsOk());
279 
280   // In the log expect the size of the ciphertext without the non-raw prefix.
281   auto raw_ciphertext =
282       absl::string_view(*ciphertext).substr(CryptoFormat::kNonRawPrefixSize);
283   EXPECT_CALL(*decryption_monitoring_client_ptr_,
284               Log(kPrimaryKeyId, raw_ciphertext.size()));
285   EXPECT_THAT((*aead)->Decrypt(*ciphertext, kAssociatedData), IsOk());
286 }
287 
288 // Test that monitoring logs encryption and decryption failures correctly.
TEST_F(AeadSetWrapperTestWithMonitoring,WrapKeysetWithMonitoringEncryptDecryptFailures)289 TEST_F(AeadSetWrapperTestWithMonitoring,
290        WrapKeysetWithMonitoringEncryptDecryptFailures) {
291   // Populate a primitive set.
292   KeysetInfo keyset_info = CreateTestKeysetInfo();
293 
294   const absl::flat_hash_map<std::string, std::string> kAnnotations = {
295       {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
296 
297   auto aead_primitive_set = absl::make_unique<PrimitiveSet<Aead>>(kAnnotations);
298 
299   // Assume encryption and decryption always fail.
300   auto mock_aead = absl::make_unique<MockAead>();
301   constexpr absl::string_view kPlaintext = "A plaintext!!";
302   constexpr absl::string_view kCiphertext = "A ciphertext!";
303   constexpr absl::string_view kAssociatedData = "Some associated data!";
304   ON_CALL(*mock_aead, Encrypt(kPlaintext, kAssociatedData))
305       .WillByDefault(Return(util::Status(absl::StatusCode::kInternal,
306                                          "Oh no encryption failed :(!")));
307   ON_CALL(*mock_aead, Decrypt(kCiphertext, kAssociatedData))
308       .WillByDefault(Return(util::Status(absl::StatusCode::kInternal,
309                                          "Oh no decryption failed :(!")));
310 
311   util::StatusOr<PrimitiveSet<Aead>::Entry<Aead>*> primary =
312       aead_primitive_set->AddPrimitive(std::move(mock_aead),
313                                        keyset_info.key_info(2));
314   ASSERT_THAT(primary, IsOk());
315   // Set the only primitive as primary.
316   ASSERT_THAT(aead_primitive_set->set_primary(*primary), IsOk());
317 
318   util::StatusOr<std::unique_ptr<Aead>> aead =
319       AeadWrapper().Wrap(std::move(aead_primitive_set));
320   ASSERT_THAT(aead, IsOk());
321 
322   // Expect encryption failure gets logged.
323   EXPECT_CALL(*encryption_monitoring_client_ptr_, LogFailure());
324   util::StatusOr<std::string> ciphertext =
325       (*aead)->Encrypt(kPlaintext, kAssociatedData);
326   EXPECT_THAT(ciphertext, Not(IsOk()));
327 
328   // We must prepend the identifier to the ciphertext to make sure our mock gets
329   // called.
330   util::StatusOr<std::string> key_identifier =
331       CryptoFormat::GetOutputPrefix(keyset_info.key_info(2));
332   ASSERT_THAT(key_identifier, IsOk());
333   std::string ciphertext_with_key_id =
334       absl::StrCat(*key_identifier, kCiphertext);
335 
336   // Expect decryption failure gets logged.
337   EXPECT_CALL(*decryption_monitoring_client_ptr_, LogFailure());
338   EXPECT_THAT(
339       (*aead)->Decrypt(ciphertext_with_key_id, kAssociatedData).status(),
340       Not(IsOk()));
341 }
342 
343 }  // namespace
344 }  // namespace tink
345 }  // namespace crypto
346