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