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_cmac_boringssl.h"
18
19 #include <cstddef>
20 #include <memory>
21 #include <string>
22 #include <vector>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/escaping.h"
29 #include "absl/strings/string_view.h"
30 #include "tink/subtle/common_enums.h"
31 #include "tink/subtle/mac/stateful_mac.h"
32 #include "tink/subtle/wycheproof_util.h"
33 #include "tink/util/secret_data.h"
34 #include "tink/util/status.h"
35 #include "tink/util/statusor.h"
36 #include "tink/util/test_matchers.h"
37
38 namespace crypto {
39 namespace tink {
40 namespace subtle {
41 namespace {
42
43 constexpr size_t kTagSize = 16;
44 constexpr size_t kSmallTagSize = 10;
45
46 constexpr absl::string_view kKeyHex = "000102030405060708090a0b0c0d0e0f";
47 constexpr absl::string_view kData = "Some data to test.";
48 constexpr absl::string_view kCmacOnEmptyInputRegularTagSizeHex =
49 "97dd6e5a882cbd564c39ae7d1c5a31aa";
50 constexpr absl::string_view kCmacOnEmptyInputSmallTagSizeHex =
51 "97dd6e5a882cbd564c39";
52 constexpr absl::string_view kCmacOnDataRegularTagSizeHex =
53 "c856e183e8dee9bb99402d54c34f3222";
54 constexpr absl::string_view kCmacOnDataSmallTagSizeHex = "c856e183e8dee9bb9940";
55
56 using ::crypto::tink::test::IsOk;
57 using ::crypto::tink::test::IsOkAndHolds;
58 using ::testing::Not;
59 using ::testing::TestWithParam;
60 using ::testing::ValuesIn;
61
TEST(StatefulCmacBoringSslTest,CmacEmptyInputRegularTagSize)62 TEST(StatefulCmacBoringSslTest, CmacEmptyInputRegularTagSize) {
63 util::SecretData key =
64 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
65 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
66 StatefulCmacBoringSsl::New(kTagSize, key);
67 ASSERT_THAT(cmac, IsOk());
68 EXPECT_THAT(
69 (*cmac)->Finalize(),
70 IsOkAndHolds(absl::HexStringToBytes(kCmacOnEmptyInputRegularTagSizeHex)));
71 }
72
TEST(StatefulCmacBoringSslTest,CmacEmptyInputSmallTag)73 TEST(StatefulCmacBoringSslTest, CmacEmptyInputSmallTag) {
74 util::SecretData key =
75 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
76 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
77 StatefulCmacBoringSsl::New(kSmallTagSize, key);
78 ASSERT_THAT(cmac, IsOk());
79 EXPECT_THAT(
80 (*cmac)->Finalize(),
81 IsOkAndHolds(absl::HexStringToBytes(kCmacOnEmptyInputSmallTagSizeHex)));
82 }
83
TEST(StatefulCmacBoringSslTest,CmacSomeDataRegularTagSize)84 TEST(StatefulCmacBoringSslTest, CmacSomeDataRegularTagSize) {
85 util::SecretData key =
86 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
87 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
88 StatefulCmacBoringSsl::New(kTagSize, key);
89 ASSERT_THAT(cmac, IsOk());
90 EXPECT_THAT((*cmac)->Update(kData), IsOk());
91 EXPECT_THAT(
92 (*cmac)->Finalize(),
93 IsOkAndHolds(absl::HexStringToBytes(kCmacOnDataRegularTagSizeHex)));
94 }
95
TEST(StatefulCmacBoringSslTest,CmacSomeDataSmallTag)96 TEST(StatefulCmacBoringSslTest, CmacSomeDataSmallTag) {
97 util::SecretData key =
98 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
99 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
100 StatefulCmacBoringSsl::New(kSmallTagSize, key);
101 ASSERT_THAT(cmac, IsOk());
102 EXPECT_THAT((*cmac)->Update(kData), IsOk());
103 EXPECT_THAT((*cmac)->Finalize(),
104 IsOkAndHolds(absl::HexStringToBytes(kCmacOnDataSmallTagSizeHex)));
105 }
106
TEST(StatefulCmacBoringSslTest,CmacMultipleUpdatesSameAsOneForWholeInputRegularTagSize)107 TEST(StatefulCmacBoringSslTest,
108 CmacMultipleUpdatesSameAsOneForWholeInputRegularTagSize) {
109 util::SecretData key =
110 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
111 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
112 StatefulCmacBoringSsl::New(kTagSize, key);
113 ASSERT_THAT(cmac, IsOk());
114 for (const std::string &token : {"Some ", "data ", "to ", "test."}) {
115 EXPECT_THAT((*cmac)->Update(token), IsOk());
116 }
117 EXPECT_THAT(
118 (*cmac)->Finalize(),
119 IsOkAndHolds(absl::HexStringToBytes(kCmacOnDataRegularTagSizeHex)));
120 }
121
TEST(StatefulCmacBoringSslTest,CmacMultipleUpdatesSameAsOneForWholeInputSmallTagSize)122 TEST(StatefulCmacBoringSslTest,
123 CmacMultipleUpdatesSameAsOneForWholeInputSmallTagSize) {
124 util::SecretData key =
125 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
126 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
127 StatefulCmacBoringSsl::New(kSmallTagSize, key);
128 ASSERT_THAT(cmac, IsOk());
129 for (const std::string &token : {"Some ", "data ", "to ", "test."}) {
130 EXPECT_THAT((*cmac)->Update(token), IsOk());
131 }
132 EXPECT_THAT((*cmac)->Finalize(),
133 IsOkAndHolds(absl::HexStringToBytes(kCmacOnDataSmallTagSizeHex)));
134 }
135
TEST(StatefulCmacFactoryTest,FactoryGeneratesValidInstances)136 TEST(StatefulCmacFactoryTest, FactoryGeneratesValidInstances) {
137 auto factory = absl::make_unique<StatefulCmacBoringSslFactory>(
138 kTagSize,
139 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex)));
140 util::StatusOr<std::unique_ptr<StatefulMac>> cmac = factory->Create();
141 ASSERT_THAT(cmac, IsOk());
142 EXPECT_THAT((*cmac)->Update(kData), IsOk());
143 EXPECT_THAT(
144 (*cmac)->Finalize(),
145 IsOkAndHolds(absl::HexStringToBytes(kCmacOnDataRegularTagSizeHex)));
146 }
147
148 struct StatefulCmacTestVector {
149 std::string key;
150 std::string msg;
151 std::string tag;
152 std::string id;
153 std::string expected_result;
154 };
155
156 // Reads the Wycheproof test vectors for AES-CMAC.
GetWycheproofCmakeTestVectors()157 std::vector<StatefulCmacTestVector> GetWycheproofCmakeTestVectors() {
158 std::unique_ptr<rapidjson::Document> root =
159 WycheproofUtil::ReadTestVectors("aes_cmac_test.json");
160 std::vector<StatefulCmacTestVector> test_vectors;
161 for (const rapidjson::Value &test_group : (*root)["testGroups"].GetArray()) {
162 // Ignore test vectors of invalid key sizes; valid sizes are {16, 32} bytes.
163 int key_size_bits = test_group["keySize"].GetInt();
164 if (key_size_bits != 128 && key_size_bits != 256) {
165 continue;
166 }
167 for (const rapidjson::Value &test : test_group["tests"].GetArray()) {
168 test_vectors.push_back({
169 /*key=*/WycheproofUtil::GetBytes(test["key"]),
170 /*msg=*/WycheproofUtil::GetBytes(test["msg"]),
171 /*tag=*/WycheproofUtil::GetBytes(test["tag"]),
172 /*id=*/absl::StrCat(test["tcId"].GetInt()),
173 /*expected_result=*/test["result"].GetString(),
174 });
175 }
176 }
177 return test_vectors;
178 }
179
180 using StatefulCmacBoringSslWycheproofTest =
181 TestWithParam<StatefulCmacTestVector>;
182
TEST_P(StatefulCmacBoringSslWycheproofTest,WycheproofTest)183 TEST_P(StatefulCmacBoringSslWycheproofTest, WycheproofTest) {
184 StatefulCmacTestVector test_vector = GetParam();
185
186 util::SecretData key =
187 util::SecretDataFromStringView(absl::HexStringToBytes(kKeyHex));
188 util::StatusOr<std::unique_ptr<StatefulMac>> cmac =
189 StatefulCmacBoringSsl::New(
190 test_vector.tag.length(),
191 util::SecretDataFromStringView(test_vector.key));
192 ASSERT_THAT(cmac, IsOk());
193 EXPECT_THAT((*cmac)->Update(test_vector.msg), IsOk());
194
195 if (test_vector.expected_result == "invalid") {
196 EXPECT_THAT((*cmac)->Finalize(), Not(IsOkAndHolds(test_vector.tag)));
197 } else {
198 EXPECT_THAT((*cmac)->Finalize(), IsOkAndHolds(test_vector.tag));
199 }
200 }
201
202 INSTANTIATE_TEST_SUITE_P(StatefulCmacBoringSslWycheproofTest,
203 StatefulCmacBoringSslWycheproofTest,
204 ValuesIn(GetWycheproofCmakeTestVectors()));
205
206 } // namespace
207 } // namespace subtle
208 } // namespace tink
209 } // namespace crypto
210