1 // Copyright 2023 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/aes_gcm_key.h"
18
19 #include <string>
20 #include <tuple>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/types/optional.h"
25 #include "tink/aead/aes_gcm_parameters.h"
26 #include "tink/partial_key_access.h"
27 #include "tink/restricted_data.h"
28 #include "tink/util/statusor.h"
29 #include "tink/util/test_matchers.h"
30
31 namespace crypto {
32 namespace tink {
33 namespace {
34
35 using ::crypto::tink::test::IsOk;
36 using ::crypto::tink::test::StatusIs;
37 using ::testing::Combine;
38 using ::testing::Eq;
39 using ::testing::Range;
40 using ::testing::TestWithParam;
41 using ::testing::Values;
42
43 struct TestCase {
44 AesGcmParameters::Variant variant;
45 absl::optional<int> id_requirement;
46 std::string output_prefix;
47 };
48
49 using AesGcmKeyTest = TestWithParam<std::tuple<int, int, TestCase>>;
50
51 INSTANTIATE_TEST_SUITE_P(
52 AesGcmKeyTestSuite, AesGcmKeyTest,
53 Combine(Values(16, 24, 32), Range(12, 16),
54 Values(TestCase{AesGcmParameters::Variant::kTink, 0x02030400,
55 std::string("\x01\x02\x03\x04\x00", 5)},
56 TestCase{AesGcmParameters::Variant::kCrunchy, 0x01030005,
57 std::string("\x00\x01\x03\x00\x05", 5)},
58 TestCase{AesGcmParameters::Variant::kNoPrefix, absl::nullopt,
59 ""})));
60
TEST_P(AesGcmKeyTest,CreateSucceeds)61 TEST_P(AesGcmKeyTest, CreateSucceeds) {
62 int key_size;
63 int iv_and_tag_size; // NOTE: There's no requirement for IV size == tag size.
64 TestCase test_case;
65 std::tie(key_size, iv_and_tag_size, test_case) = GetParam();
66
67 util::StatusOr<AesGcmParameters> params =
68 AesGcmParameters::Builder()
69 .SetKeySizeInBytes(key_size)
70 .SetIvSizeInBytes(iv_and_tag_size)
71 .SetTagSizeInBytes(iv_and_tag_size)
72 .SetVariant(test_case.variant)
73 .Build();
74 ASSERT_THAT(params, IsOk());
75
76 RestrictedData secret = RestrictedData(key_size);
77 util::StatusOr<AesGcmKey> key = AesGcmKey::Create(
78 *params, secret, test_case.id_requirement, GetPartialKeyAccess());
79 ASSERT_THAT(key, IsOk());
80
81 EXPECT_THAT(key->GetParameters(), Eq(*params));
82 EXPECT_THAT(key->GetIdRequirement(), Eq(test_case.id_requirement));
83 EXPECT_THAT(key->GetOutputPrefix(), Eq(test_case.output_prefix));
84 }
85
TEST(AesGcmKeyTest,CreateKeyWithMismatchedKeySizeFails)86 TEST(AesGcmKeyTest, CreateKeyWithMismatchedKeySizeFails) {
87 // Key size parameter is 32 bytes.
88 util::StatusOr<AesGcmParameters> params =
89 AesGcmParameters::Builder()
90 .SetKeySizeInBytes(32)
91 .SetIvSizeInBytes(16)
92 .SetTagSizeInBytes(16)
93 .SetVariant(AesGcmParameters::Variant::kTink)
94 .Build();
95 ASSERT_THAT(params, IsOk());
96
97 // Key material is 16 bytes (another valid key length).
98 RestrictedData mismatched_secret = RestrictedData(/*num_random_bytes=*/16);
99
100 EXPECT_THAT(AesGcmKey::Create(*params, mismatched_secret,
101 /*id_requirement=*/123, GetPartialKeyAccess())
102 .status(),
103 StatusIs(absl::StatusCode::kInvalidArgument));
104 }
105
TEST(AesGcmKeyTest,CreateKeyWithInvalidIdRequirementFails)106 TEST(AesGcmKeyTest, CreateKeyWithInvalidIdRequirementFails) {
107 util::StatusOr<AesGcmParameters> no_prefix_params =
108 AesGcmParameters::Builder()
109 .SetKeySizeInBytes(32)
110 .SetIvSizeInBytes(16)
111 .SetTagSizeInBytes(16)
112 .SetVariant(AesGcmParameters::Variant::kNoPrefix)
113 .Build();
114 ASSERT_THAT(no_prefix_params, IsOk());
115
116 util::StatusOr<AesGcmParameters> tink_params =
117 AesGcmParameters::Builder()
118 .SetKeySizeInBytes(32)
119 .SetIvSizeInBytes(16)
120 .SetTagSizeInBytes(16)
121 .SetVariant(AesGcmParameters::Variant::kTink)
122 .Build();
123 ASSERT_THAT(tink_params, IsOk());
124
125 RestrictedData secret = RestrictedData(/*num_random_bytes=*/32);
126
127 EXPECT_THAT(AesGcmKey::Create(*no_prefix_params, secret,
128 /*id_requirement=*/123, GetPartialKeyAccess())
129 .status(),
130 StatusIs(absl::StatusCode::kInvalidArgument));
131 EXPECT_THAT(
132 AesGcmKey::Create(*tink_params, secret,
133 /*id_requirement=*/absl::nullopt, GetPartialKeyAccess())
134 .status(),
135 StatusIs(absl::StatusCode::kInvalidArgument));
136 }
137
TEST_P(AesGcmKeyTest,GetKeyBytes)138 TEST_P(AesGcmKeyTest, GetKeyBytes) {
139 int key_size;
140 int iv_and_tag_size; // NOTE: There's no requirement for IV size == tag size.
141 TestCase test_case;
142 std::tie(key_size, iv_and_tag_size, test_case) = GetParam();
143
144 util::StatusOr<AesGcmParameters> params =
145 AesGcmParameters::Builder()
146 .SetKeySizeInBytes(key_size)
147 .SetIvSizeInBytes(iv_and_tag_size)
148 .SetTagSizeInBytes(iv_and_tag_size)
149 .SetVariant(test_case.variant)
150 .Build();
151 ASSERT_THAT(params, IsOk());
152
153 RestrictedData secret = RestrictedData(key_size);
154
155 util::StatusOr<AesGcmKey> key = AesGcmKey::Create(
156 *params, secret, test_case.id_requirement, GetPartialKeyAccess());
157 ASSERT_THAT(key, IsOk());
158
159 EXPECT_THAT(key->GetKeyBytes(GetPartialKeyAccess()), Eq(secret));
160 }
161
TEST_P(AesGcmKeyTest,KeyEquals)162 TEST_P(AesGcmKeyTest, KeyEquals) {
163 int key_size;
164 int iv_and_tag_size; // NOTE: There's no requirement for IV size == tag size.
165 TestCase test_case;
166 std::tie(key_size, iv_and_tag_size, test_case) = GetParam();
167
168 util::StatusOr<AesGcmParameters> params =
169 AesGcmParameters::Builder()
170 .SetKeySizeInBytes(key_size)
171 .SetIvSizeInBytes(iv_and_tag_size)
172 .SetTagSizeInBytes(iv_and_tag_size)
173 .SetVariant(test_case.variant)
174 .Build();
175 ASSERT_THAT(params, IsOk());
176
177 RestrictedData secret = RestrictedData(key_size);
178 util::StatusOr<AesGcmKey> key = AesGcmKey::Create(
179 *params, secret, test_case.id_requirement, GetPartialKeyAccess());
180 ASSERT_THAT(key, IsOk());
181
182 util::StatusOr<AesGcmKey> other_key = AesGcmKey::Create(
183 *params, secret, test_case.id_requirement, GetPartialKeyAccess());
184 ASSERT_THAT(other_key, IsOk());
185
186 EXPECT_TRUE(*key == *other_key);
187 EXPECT_TRUE(*other_key == *key);
188 EXPECT_FALSE(*key != *other_key);
189 EXPECT_FALSE(*other_key != *key);
190 }
191
TEST(AesGcmKeyTest,DifferentVariantNotEqual)192 TEST(AesGcmKeyTest, DifferentVariantNotEqual) {
193 util::StatusOr<AesGcmParameters> crunchy_params =
194 AesGcmParameters::Builder()
195 .SetKeySizeInBytes(32)
196 .SetIvSizeInBytes(16)
197 .SetTagSizeInBytes(16)
198 .SetVariant(AesGcmParameters::Variant::kCrunchy)
199 .Build();
200 ASSERT_THAT(crunchy_params, IsOk());
201
202 util::StatusOr<AesGcmParameters> tink_params =
203 AesGcmParameters::Builder()
204 .SetKeySizeInBytes(32)
205 .SetIvSizeInBytes(16)
206 .SetTagSizeInBytes(16)
207 .SetVariant(AesGcmParameters::Variant::kTink)
208 .Build();
209 ASSERT_THAT(tink_params, IsOk());
210
211 RestrictedData secret = RestrictedData(/*num_random_bytes=*/32);
212
213 util::StatusOr<AesGcmKey> key =
214 AesGcmKey::Create(*crunchy_params, secret, /*id_requirement=*/0x01020304,
215 GetPartialKeyAccess());
216 ASSERT_THAT(key, IsOk());
217
218 util::StatusOr<AesGcmKey> other_key =
219 AesGcmKey::Create(*tink_params, secret, /*id_requirement=*/0x01020304,
220 GetPartialKeyAccess());
221 ASSERT_THAT(other_key, IsOk());
222
223 EXPECT_TRUE(*key != *other_key);
224 EXPECT_TRUE(*other_key != *key);
225 EXPECT_FALSE(*key == *other_key);
226 EXPECT_FALSE(*other_key == *key);
227 }
228
TEST(AesGcmKeyTest,DifferentSecretDataNotEqual)229 TEST(AesGcmKeyTest, DifferentSecretDataNotEqual) {
230 util::StatusOr<AesGcmParameters> params =
231 AesGcmParameters::Builder()
232 .SetKeySizeInBytes(32)
233 .SetIvSizeInBytes(16)
234 .SetTagSizeInBytes(16)
235 .SetVariant(AesGcmParameters::Variant::kTink)
236 .Build();
237 ASSERT_THAT(params, IsOk());
238
239 RestrictedData secret1 = RestrictedData(/*num_random_bytes=*/32);
240 RestrictedData secret2 = RestrictedData(/*num_random_bytes=*/32);
241
242 util::StatusOr<AesGcmKey> key = AesGcmKey::Create(
243 *params, secret1, /*id_requirement=*/0x01020304, GetPartialKeyAccess());
244 ASSERT_THAT(key, IsOk());
245
246 util::StatusOr<AesGcmKey> other_key = AesGcmKey::Create(
247 *params, secret2, /*id_requirement=*/0x01020304, GetPartialKeyAccess());
248 ASSERT_THAT(other_key, IsOk());
249
250 EXPECT_TRUE(*key != *other_key);
251 EXPECT_TRUE(*other_key != *key);
252 EXPECT_FALSE(*key == *other_key);
253 EXPECT_FALSE(*other_key == *key);
254 }
255
TEST(AesGcmKeyTest,DifferentIdRequirementNotEqual)256 TEST(AesGcmKeyTest, DifferentIdRequirementNotEqual) {
257 util::StatusOr<AesGcmParameters> params =
258 AesGcmParameters::Builder()
259 .SetKeySizeInBytes(32)
260 .SetIvSizeInBytes(16)
261 .SetTagSizeInBytes(16)
262 .SetVariant(AesGcmParameters::Variant::kTink)
263 .Build();
264 ASSERT_THAT(params, IsOk());
265
266 RestrictedData secret = RestrictedData(/*num_random_bytes=*/32);
267
268 util::StatusOr<AesGcmKey> key = AesGcmKey::Create(
269 *params, secret, /*id_requirement=*/0x01020304, GetPartialKeyAccess());
270 ASSERT_THAT(key, IsOk());
271
272 util::StatusOr<AesGcmKey> other_key = AesGcmKey::Create(
273 *params, secret, /*id_requirement=*/0x02030405, GetPartialKeyAccess());
274 ASSERT_THAT(other_key, IsOk());
275
276 EXPECT_TRUE(*key != *other_key);
277 EXPECT_TRUE(*other_key != *key);
278 EXPECT_FALSE(*key == *other_key);
279 EXPECT_FALSE(*other_key == *key);
280 }
281
282 } // namespace
283 } // namespace tink
284 } // namespace crypto
285