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/subtle/stateful_hmac_boringssl.h"
18
19 #include <cstddef>
20 #include <string>
21 #include <utility>
22
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/memory/memory.h"
26 #include "absl/status/status.h"
27 #include "tink/subtle/common_enums.h"
28 #include "tink/subtle/wycheproof_util.h"
29 #include "tink/util/secret_data.h"
30 #include "tink/util/status.h"
31 #include "tink/util/statusor.h"
32 #include "tink/util/test_matchers.h"
33 #include "tink/util/test_util.h"
34
35 namespace crypto {
36 namespace tink {
37 namespace subtle {
38 namespace {
39
40 constexpr size_t kTagSize = 16;
41 constexpr size_t kSmallTagSize = 10;
42
43 using ::crypto::tink::test::IsOk;
44 using ::crypto::tink::test::StatusIs;
45 using ::testing::HasSubstr;
46 using ::testing::StrEq;
47
EmptyHmac(HashType hash_type,uint32_t tag_size,std::string key,std::string expected)48 void EmptyHmac(HashType hash_type, uint32_t tag_size, std::string key,
49 std::string expected) {
50 auto hmac_result = StatefulHmacBoringSsl::New(
51 hash_type, tag_size, util::SecretDataFromStringView(key));
52 EXPECT_THAT(hmac_result, IsOk());
53 auto hmac = std::move(hmac_result.value());
54 auto result = hmac->Finalize();
55 EXPECT_THAT(result, IsOk());
56
57 auto tag = result.value();
58 EXPECT_EQ(tag.size(), tag_size);
59 EXPECT_EQ(tag, expected);
60 }
61
TEST(StatefulHmacBoringSslTest,testEmpty)62 TEST(StatefulHmacBoringSslTest, testEmpty) {
63 std::string key(test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
64
65 std::string expected_256(
66 test::HexDecodeOrDie("07eff8b326b7798c9ccfcbdbe579489a"));
67 EmptyHmac(HashType::SHA256, kTagSize, key, expected_256);
68
69 std::string expected_512(
70 test::HexDecodeOrDie("2fec800ca276c44985a35aec92067e5e"));
71 EmptyHmac(HashType::SHA512, kTagSize, key, expected_512);
72
73 std::string expected_256_small(test::HexDecodeOrDie("07eff8b326b7798c9ccf"));
74 EmptyHmac(HashType::SHA256, kSmallTagSize, key, expected_256_small);
75
76 std::string expected_512_small(test::HexDecodeOrDie("2fec800ca276c44985a3"));
77 EmptyHmac(HashType::SHA512, kSmallTagSize, key, expected_512_small);
78 }
79
BasicHmac(HashType hash_type,uint32_t tag_size,std::string key,std::string data,std::string expected)80 void BasicHmac(HashType hash_type, uint32_t tag_size, std::string key,
81 std::string data, std::string expected) {
82 auto hmac_result = StatefulHmacBoringSsl::New(
83 hash_type, tag_size, util::SecretDataFromStringView(key));
84 EXPECT_THAT(hmac_result, IsOk());
85 auto hmac = std::move(hmac_result.value());
86
87 auto update_result = hmac->Update(data);
88 EXPECT_THAT(update_result, IsOk());
89 auto result = hmac->Finalize();
90 EXPECT_THAT(result, IsOk());
91
92 auto tag = result.value();
93 EXPECT_EQ(tag.size(), tag_size);
94 EXPECT_EQ(tag, expected);
95 }
96
TEST(StatefulHmacBoringSslTest,testBasic)97 TEST(StatefulHmacBoringSslTest, testBasic) {
98 std::string key(test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
99 std::string data = "Some data to test.";
100
101 std::string expected_256(
102 test::HexDecodeOrDie("1d6eb74bc283f7947e92c72bd985ce6e"));
103 BasicHmac(HashType::SHA256, kTagSize, key, data, expected_256);
104
105 std::string expected_512(
106 test::HexDecodeOrDie("72b8ff800f57f9aeec41265a29b69b6a"));
107 BasicHmac(HashType::SHA512, kTagSize, key, data, expected_512);
108
109 std::string expected_256_small(test::HexDecodeOrDie("1d6eb74bc283f7947e92"));
110 BasicHmac(HashType::SHA256, kSmallTagSize, key, data, expected_256_small);
111
112 std::string expected_512_small(test::HexDecodeOrDie("72b8ff800f57f9aeec41"));
113 BasicHmac(HashType::SHA512, kSmallTagSize, key, data, expected_512_small);
114 }
115
MultipleUpdateHmac(HashType hash_type,uint32_t tag_size,std::string key,std::string data1,std::string data2,std::string data3,std::string data4,std::string expected)116 void MultipleUpdateHmac(HashType hash_type, uint32_t tag_size, std::string key,
117 std::string data1, std::string data2, std::string data3,
118 std::string data4, std::string expected) {
119 auto hmac_result = StatefulHmacBoringSsl::New(
120 hash_type, tag_size, util::SecretDataFromStringView(key));
121 EXPECT_THAT(hmac_result, IsOk());
122 auto hmac = std::move(hmac_result.value());
123
124 auto update_1 = hmac->Update(data1);
125 EXPECT_THAT(update_1, IsOk());
126 auto update_2 = hmac->Update(data2);
127 EXPECT_THAT(update_2, IsOk());
128 auto update_3 = hmac->Update(data3);
129 EXPECT_THAT(update_3, IsOk());
130 auto update_4 = hmac->Update(data4);
131 EXPECT_THAT(update_4, IsOk());
132
133 auto result = hmac->Finalize();
134 EXPECT_THAT(result, IsOk());
135
136 auto tag = result.value();
137 EXPECT_EQ(tag.size(), tag_size);
138 EXPECT_EQ(tag, expected);
139 }
140
TEST(StatefulHmacBoringSslTest,testMultipleUpdates)141 TEST(StatefulHmacBoringSslTest, testMultipleUpdates) {
142 std::string key(test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
143 std::string data1 = "Some ", data2 = "data ", data3 = "to ", data4 = "test.";
144
145 // The tags are the same as the tags in testBasic, since they have the same
146 // key and the same input, but testMultipleUpdates uses multiple updates.
147
148 std::string expected_256(
149 test::HexDecodeOrDie("1d6eb74bc283f7947e92c72bd985ce6e"));
150 MultipleUpdateHmac(HashType::SHA256, kTagSize, key, data1, data2, data3,
151 data4, expected_256);
152
153 std::string expected_512(
154 test::HexDecodeOrDie("72b8ff800f57f9aeec41265a29b69b6a"));
155 MultipleUpdateHmac(HashType::SHA512, kTagSize, key, data1, data2, data3,
156 data4, expected_512);
157
158 std::string expected_256_small(test::HexDecodeOrDie("1d6eb74bc283f7947e92"));
159 MultipleUpdateHmac(HashType::SHA256, kSmallTagSize, key, data1, data2, data3,
160 data4, expected_256_small);
161
162 std::string expected_512_small(test::HexDecodeOrDie("72b8ff800f57f9aeec41"));
163 MultipleUpdateHmac(HashType::SHA512, kSmallTagSize, key, data1, data2, data3,
164 data4, expected_512_small);
165 }
166
TEST(StatefulHmacBoringSslTest,testInvalidKeySizes)167 TEST(StatefulHmacBoringSslTest, testInvalidKeySizes) {
168 size_t tag_size = 16;
169
170 for (int keysize = 0; keysize < 65; keysize++) {
171 std::string key(keysize, 'x');
172 auto hmac_result = StatefulHmacBoringSsl::New(
173 HashType::SHA256, tag_size, util::SecretDataFromStringView(key));
174 if (keysize >= 16) {
175 EXPECT_THAT(hmac_result, IsOk());
176 } else {
177 EXPECT_THAT(hmac_result.status(),
178 StatusIs(absl::StatusCode::kInvalidArgument,
179 HasSubstr("invalid key size")));
180 }
181 }
182 }
183
TEST(StatefulCmacFactoryTest,createsObjects)184 TEST(StatefulCmacFactoryTest, createsObjects) {
185 std::string key(test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
186 std::string data = "Some data to test.";
187
188 std::string expected(
189 test::HexDecodeOrDie("1d6eb74bc283f7947e92c72bd985ce6e"));
190 BasicHmac(HashType::SHA256, kTagSize, key, data, expected);
191 auto factory = absl::make_unique<StatefulHmacBoringSslFactory>(
192 HashType::SHA256, kTagSize, util::SecretDataFromStringView(key));
193 auto stateful_hmac_or = factory->Create();
194 ASSERT_THAT(stateful_hmac_or, IsOk());
195 auto stateful_hmac = std::move(stateful_hmac_or.value());
196 EXPECT_THAT(stateful_hmac->Update(data), IsOk());
197 auto output_or = stateful_hmac->Finalize();
198 ASSERT_THAT(output_or, IsOk());
199 auto output = output_or.value();
200 EXPECT_THAT(output, StrEq(expected));
201 }
202
203 class StatefulHmacBoringSslTestVectorTest
204 : public ::testing::TestWithParam<std::pair<int, std::string>> {
205 public:
206 // Utility to simplify testing with test vectors.
207 // Arguments and result are hexadecimal.
StatefulHmacVerifyHex(const std::string & key_hex,const std::string & msg_hex,const std::string & tag_hex)208 void StatefulHmacVerifyHex(const std::string &key_hex,
209 const std::string &msg_hex,
210 const std::string &tag_hex) {
211 std::string key = test::HexDecodeOrDie(key_hex);
212 std::string tag = test::HexDecodeOrDie(tag_hex);
213 std::string msg = test::HexDecodeOrDie(msg_hex);
214 auto create_result = StatefulHmacBoringSsl::New(
215 HashType::SHA1, tag.size(), util::SecretDataFromStringView(key));
216 EXPECT_THAT(create_result, IsOk());
217 auto hmac = std::move(create_result.value());
218
219 auto update_result = hmac->Update(msg);
220 EXPECT_THAT(update_result, IsOk());
221
222 auto finalize_result = hmac->Finalize();
223 EXPECT_THAT(finalize_result, IsOk());
224 auto result = finalize_result.value();
225
226 EXPECT_EQ(result, tag);
227 }
228 };
229
230 // Wycheproof HMAC tests are not enabled because the test vectors are in
231 // "rc" (release candidate) state, and are not yet exported for use.
232 // TODO(cathieyun): re-enable Wycheproof HMAC tests once vectors are exported.
233
234 /*
235 // Test with test vectors from Wycheproof project.
236 bool WycheproofTest(const rapidjson::Document &root, HashType hash_type) {
237 int errors = 0;
238 for (const rapidjson::Value &test_group : root["testGroups"].GetArray()) {
239 // Get the key size in bytes. Wycheproof contains tests for keys smaller
240 // than MIN_KEY_SIZE, which is 16, so the test will skip those.
241 if (test_group["keySize"].GetInt() / 8 < 16) {
242 continue;
243 }
244 for (const rapidjson::Value &test : test_group["tests"].GetArray()) {
245 std::string comment = test["comment"].GetString();
246 std::string key = WycheproofUtil::GetBytes(test["key"]);
247 std::string msg = WycheproofUtil::GetBytes(test["msg"]);
248 std::string tag = WycheproofUtil::GetBytes(test["tag"]);
249 std::string id = absl::StrCat(test["tcId"].GetInt());
250 std::string expected = test["result"].GetString();
251
252 auto create_result =
253 StatefulHmacBoringSsl::New(hash_type, tag.length(), key);
254 EXPECT_THAT(create_result, IsOk());
255 auto hmac = std::move(create_result.value());
256
257 auto update_result = hmac->Update(msg);
258 EXPECT_THAT(update_result, IsOk());
259
260 auto finalize_result = hmac->Finalize();
261 auto result = finalize_result.value();
262
263 bool success = result == tag;
264 if (success) {
265 // std::string result_tag = result.value();
266 if (expected == "invalid") {
267 ADD_FAILURE() << "verified incorrect tag:" << id;
268 errors++;
269 }
270 } else {
271 if (expected == "valid") {
272 ADD_FAILURE() << "Could not create tag for test with tcId:" << id
273 << " tag_size:" << tag.length()
274 << " key_size:" << key.length() << " error:" << result;
275 errors++;
276 }
277 }
278 }
279 }
280 return errors == 0;
281 }
282
283 TEST_F(StatefulHmacBoringSslTest, TestVectors) {
284 // Test Hmac with SHA256
285 std::unique_ptr<rapidjson::Document> root256 =
286 WycheproofUtil::ReadTestVectors("hmac_sha256_test.json");
287 ASSERT_TRUE(WycheproofTest(*root256, HashType::SHA256));
288
289 // Test Hmac with SHA512
290 std::unique_ptr<rapidjson::Document> root512 =
291 WycheproofUtil::ReadTestVectors("hmac_sha512_test.json");
292 ASSERT_TRUE(WycheproofTest(*root512, HashType::SHA512));
293 }
294 */
295
296 } // namespace
297 } // namespace subtle
298 } // namespace tink
299 } // namespace crypto
300