1 // Copyright 2020 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/aead/cord_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/memory/memory.h"
28 #include "absl/status/status.h"
29 #include "absl/strings/cord.h"
30 #include "absl/strings/cord_test_helpers.h"
31 #include "absl/strings/str_split.h"
32 #include "absl/strings/string_view.h"
33 #include "tink/aead/cord_aead.h"
34 #include "tink/primitive_set.h"
35 #include "tink/util/status.h"
36 #include "tink/util/test_matchers.h"
37 #include "tink/util/test_util.h"
38 #include "proto/tink.pb.h"
39
40 using ::crypto::tink::test::DummyCordAead;
41 using ::crypto::tink::test::IsOk;
42 using ::crypto::tink::test::StatusIs;
43 using ::google::crypto::tink::KeysetInfo;
44 using ::google::crypto::tink::KeyStatusType;
45 using ::google::crypto::tink::OutputPrefixType;
46
47 namespace crypto {
48 namespace tink {
49 namespace {
50
TEST(AeadSetWrapperTest,WrapNullptr)51 TEST(AeadSetWrapperTest, WrapNullptr) {
52 CordAeadWrapper wrapper;
53 auto aead_result = wrapper.Wrap(nullptr);
54 EXPECT_FALSE(aead_result.ok());
55 EXPECT_EQ(absl::StatusCode::kInternal, aead_result.status().code());
56 EXPECT_PRED_FORMAT2(testing::IsSubstring, "non-NULL",
57 std::string(aead_result.status().message()));
58 }
59
TEST(AeadSetWrapperTest,WrapEmpty)60 TEST(AeadSetWrapperTest, WrapEmpty) {
61 CordAeadWrapper wrapper;
62 auto aead_result = wrapper.Wrap(absl::make_unique<PrimitiveSet<CordAead>>());
63 EXPECT_FALSE(aead_result.ok());
64 EXPECT_EQ(absl::StatusCode::kInvalidArgument, aead_result.status().code());
65 EXPECT_PRED_FORMAT2(testing::IsSubstring, "no primary",
66 std::string(aead_result.status().message()));
67 }
68
setup_keyset()69 std::unique_ptr<PrimitiveSet<CordAead>> setup_keyset() {
70 KeysetInfo::KeyInfo* key_info;
71 KeysetInfo keyset_info;
72
73 uint32_t key_id_0 = 1234543;
74 key_info = keyset_info.add_key_info();
75 key_info->set_output_prefix_type(OutputPrefixType::TINK);
76 key_info->set_key_id(key_id_0);
77 key_info->set_status(KeyStatusType::ENABLED);
78 std::string aead_name_0 = "aead0";
79 std::unique_ptr<PrimitiveSet<CordAead>> aead_set(
80 new PrimitiveSet<CordAead>());
81 std::unique_ptr<CordAead> aead =
82 absl::make_unique<DummyCordAead>(aead_name_0);
83 auto entry_result =
84 aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
85 auto aead_set_result = aead_set->set_primary(entry_result.value());
86 return aead_set;
87 }
88
TEST(AeadSetWrapperTest,WrapperEncryptDecrypt)89 TEST(AeadSetWrapperTest, WrapperEncryptDecrypt) {
90 // Wrap aead_set and test the resulting Aead.
91 auto aead_set = setup_keyset();
92 CordAeadWrapper wrapper;
93 auto aead_result = wrapper.Wrap(std::move(aead_set));
94 ASSERT_THAT(aead_result, IsOk());
95 auto aead = std::move(aead_result.value());
96 absl::Cord plaintext;
97 plaintext.Append("some_plaintext");
98 absl::Cord aad;
99 aad.Append("some_aad");
100
101 auto encrypt_result = aead->Encrypt(plaintext, aad);
102 EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status();
103 absl::Cord ciphertext = encrypt_result.value();
104
105 auto decrypt_result = aead->Decrypt(ciphertext, aad);
106 EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status();
107 EXPECT_EQ(plaintext, decrypt_result.value());
108 }
109
TEST(AeadSetWrapperTest,WrapperEncryptDecryptMultipleKeys)110 TEST(AeadSetWrapperTest, WrapperEncryptDecryptMultipleKeys) {
111 // Wrap aead_set and test the resulting Aead.
112 auto aead_set = setup_keyset();
113
114 // Encrypt with the primary key
115 absl::Cord plaintext;
116 plaintext.Append("some_plaintext");
117 absl::Cord aad;
118 aad.Append("some_aad");
119 auto encrypt_result =
120 aead_set->get_primary()->get_primitive().Encrypt(plaintext, aad);
121 EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status();
122 absl::Cord ciphertext;
123 ciphertext.Append(aead_set->get_primary()->get_identifier());
124 ciphertext.Append(encrypt_result.value());
125
126 // Add a second key
127 KeysetInfo::KeyInfo* key_info;
128 KeysetInfo keyset_info;
129 uint32_t key_id = 42;
130 key_info = keyset_info.add_key_info();
131 key_info->set_output_prefix_type(OutputPrefixType::TINK);
132 key_info->set_key_id(key_id);
133 key_info->set_status(KeyStatusType::ENABLED);
134 std::string aead_name = "aead1";
135 std::unique_ptr<CordAead> aead = absl::make_unique<DummyCordAead>(aead_name);
136 auto entry_result =
137 aead_set->AddPrimitive(std::move(aead), keyset_info.key_info(0));
138 EXPECT_TRUE(entry_result.ok()) << entry_result.status();
139
140 // Wrap the primitive set
141 CordAeadWrapper wrapper;
142 auto aead_result = wrapper.Wrap(std::move(aead_set));
143 ASSERT_THAT(aead_result, IsOk());
144 aead = std::move(aead_result.value());
145
146 // Encrypt with the wrapped AEAD and check if result was equal to the
147 // encryption with the primary key.
148 auto encrypt_wrap_result = aead->Encrypt(plaintext, aad);
149 EXPECT_TRUE(encrypt_wrap_result.ok()) << encrypt_wrap_result.status();
150 EXPECT_EQ(ciphertext, encrypt_wrap_result.value());
151 }
152
TEST(AeadSetWrapperTest,WrapperEncryptDecryptManyChunks)153 TEST(AeadSetWrapperTest, WrapperEncryptDecryptManyChunks) {
154 // Wrap aead_set and test the resulting Aead.
155 auto aead_set = setup_keyset();
156 CordAeadWrapper wrapper;
157 auto aead_result = wrapper.Wrap(std::move(aead_set));
158 ASSERT_THAT(aead_result, IsOk());
159 auto aead = std::move(aead_result.value());
160
161 std::string plaintext = "";
162 for (int i = 0; i < 1000; i++) {
163 plaintext += "chunk" + std::to_string(i);
164 }
165 absl::Cord plaintext_cord =
166 absl::MakeFragmentedCord(absl::StrSplit(plaintext, absl::ByLength(5)));
167 absl::Cord aad;
168 aad.Append("some_aad");
169
170 auto encrypt_result = aead->Encrypt(plaintext_cord, aad);
171 EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status();
172 absl::Cord ciphertext = encrypt_result.value();
173
174 auto decrypt_result = aead->Decrypt(ciphertext, aad);
175 EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status();
176 EXPECT_EQ(plaintext, decrypt_result.value());
177 }
178
TEST(AeadSetWrapperTest,WrapperEncryptBadDecrypt)179 TEST(AeadSetWrapperTest, WrapperEncryptBadDecrypt) {
180 // Wrap aead_set and test the resulting Aead.
181 auto aead_set = setup_keyset();
182 CordAeadWrapper wrapper;
183 auto aead_result = wrapper.Wrap(std::move(aead_set));
184 ASSERT_THAT(aead_result, IsOk());
185 auto aead = std::move(aead_result.value());
186 absl::Cord plaintext;
187 plaintext.Append("some_plaintext");
188 absl::Cord aad;
189 aad.Append("some_aad");
190
191 absl::Cord bad_ciphertext;
192 bad_ciphertext.Append("some bad ciphertext");
193 auto decrypt_result = aead->Decrypt(bad_ciphertext, aad);
194 EXPECT_FALSE(decrypt_result.ok());
195 EXPECT_EQ(absl::StatusCode::kInvalidArgument, decrypt_result.status().code());
196 EXPECT_THAT(decrypt_result.status(),
197 StatusIs(absl::StatusCode::kInvalidArgument,
198 testing::HasSubstr("decryption failed")));
199 }
200
201 } // namespace
202 } // namespace tink
203 } // namespace crypto
204