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