1 // Copyright 2017 Google Inc.
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/aes_eax_boringssl.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "openssl/err.h"
28 #include "tink/config/tink_fips.h"
29 #include "tink/subtle/wycheproof_util.h"
30 #include "tink/util/secret_data.h"
31 #include "tink/util/status.h"
32 #include "tink/util/statusor.h"
33 #include "tink/util/test_matchers.h"
34 #include "tink/util/test_util.h"
35
36 namespace crypto {
37 namespace tink {
38 namespace subtle {
39 namespace {
40
41 using ::crypto::tink::test::StatusIs;
42
TEST(AesEaxBoringSslTest,TestBasic)43 TEST(AesEaxBoringSslTest, TestBasic) {
44 if (IsFipsModeEnabled()) {
45 GTEST_SKIP() << "Not supported in FIPS-only mode";
46 }
47
48 util::SecretData key = util::SecretDataFromStringView(
49 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
50 size_t nonce_size = 12;
51 auto res = AesEaxBoringSsl::New(key, nonce_size);
52 EXPECT_TRUE(res.ok()) << res.status();
53 auto cipher = std::move(res.value());
54 std::string message = "Some data to encrypt.";
55 std::string associated_data = "Some data to authenticate.";
56 auto ct = cipher->Encrypt(message, associated_data);
57 EXPECT_TRUE(ct.ok()) << ct.status();
58 EXPECT_EQ(ct.value().size(), message.size() + nonce_size + 16);
59 auto pt = cipher->Decrypt(ct.value(), associated_data);
60 EXPECT_TRUE(pt.ok()) << pt.status();
61 EXPECT_EQ(pt.value(), message);
62 }
63
TEST(AesEaxBoringSslTest,TestMessageSize)64 TEST(AesEaxBoringSslTest, TestMessageSize) {
65 if (IsFipsModeEnabled()) {
66 GTEST_SKIP() << "Not supported in FIPS-only mode";
67 }
68
69 util::SecretData key = util::SecretDataFromStringView(
70 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
71 size_t nonce_size = 12;
72 auto res = AesEaxBoringSsl::New(key, nonce_size);
73 EXPECT_TRUE(res.ok()) << res.status();
74 auto cipher = std::move(res.value());
75 for (size_t size = 0; size < 260; size++) {
76 std::string message(size, 'x');
77 std::string associated_data = "";
78 auto ct = cipher->Encrypt(message, associated_data);
79 EXPECT_TRUE(ct.ok()) << ct.status();
80 EXPECT_EQ(ct.value().size(), message.size() + nonce_size + 16);
81 auto pt = cipher->Decrypt(ct.value(), associated_data);
82 EXPECT_TRUE(pt.ok()) << pt.status();
83 EXPECT_EQ(pt.value(), message);
84 }
85 }
86
TEST(AesEaxBoringSslTest,TestAssociatedDataSize)87 TEST(AesEaxBoringSslTest, TestAssociatedDataSize) {
88 if (IsFipsModeEnabled()) {
89 GTEST_SKIP() << "Not supported in FIPS-only mode";
90 }
91
92 util::SecretData key = util::SecretDataFromStringView(
93 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
94 size_t nonce_size = 12;
95 auto res = AesEaxBoringSsl::New(key, nonce_size);
96 EXPECT_TRUE(res.ok()) << res.status();
97 auto cipher = std::move(res.value());
98 for (size_t size = 0; size < 260; size++) {
99 std::string message("Some message");
100 std::string associated_data(size, 'x');
101 auto ct = cipher->Encrypt(message, associated_data);
102 EXPECT_TRUE(ct.ok()) << ct.status();
103 EXPECT_EQ(ct.value().size(), message.size() + nonce_size + 16);
104 auto pt = cipher->Decrypt(ct.value(), associated_data);
105 EXPECT_TRUE(pt.ok()) << pt.status();
106 EXPECT_EQ(pt.value(), message);
107 }
108 }
109
TEST(AesEaxBoringSslTest,TestLongNonce)110 TEST(AesEaxBoringSslTest, TestLongNonce) {
111 if (IsFipsModeEnabled()) {
112 GTEST_SKIP() << "Not supported in FIPS-only mode";
113 }
114
115 util::SecretData key = util::SecretDataFromStringView(
116 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
117 size_t nonce_size = 16;
118 auto res = AesEaxBoringSsl::New(key, nonce_size);
119 EXPECT_TRUE(res.ok()) << res.status();
120 auto cipher = std::move(res.value());
121 std::string message = "Some data to encrypt.";
122 std::string associated_data = "Some associated data.";
123 auto ct = cipher->Encrypt(message, associated_data);
124 EXPECT_TRUE(ct.ok()) << ct.status();
125 EXPECT_EQ(ct.value().size(), message.size() + nonce_size + 16);
126 auto pt = cipher->Decrypt(ct.value(), associated_data);
127 EXPECT_TRUE(pt.ok()) << pt.status();
128 EXPECT_EQ(pt.value(), message);
129 }
130
TEST(AesEaxBoringSslTest,TestModification)131 TEST(AesEaxBoringSslTest, TestModification) {
132 if (IsFipsModeEnabled()) {
133 GTEST_SKIP() << "Not supported in FIPS-only mode";
134 }
135
136 size_t nonce_size = 12;
137 util::SecretData key = util::SecretDataFromStringView(
138 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
139 auto cipher = std::move(AesEaxBoringSsl::New(key, nonce_size).value());
140 std::string message = "Some data to encrypt.";
141 std::string associated_data = "Some data to authenticate.";
142 std::string ct = cipher->Encrypt(message, associated_data).value();
143 EXPECT_TRUE(cipher->Decrypt(ct, associated_data).ok());
144 // Modify the ciphertext
145 for (size_t i = 0; i < ct.size() * 8; i++) {
146 std::string modified_ct = ct;
147 modified_ct[i / 8] ^= 1 << (i % 8);
148 EXPECT_FALSE(cipher->Decrypt(modified_ct, associated_data).ok()) << i;
149 }
150 // Modify the associated data
151 for (size_t i = 0; i < associated_data.size() * 8; i++) {
152 std::string modified_associated_data = associated_data;
153 modified_associated_data[i / 8] ^= 1 << (i % 8);
154 auto decrypted = cipher->Decrypt(ct, modified_associated_data);
155 EXPECT_FALSE(decrypted.ok()) << i << " pt:" << decrypted.value();
156 }
157 // Truncate the ciphertext
158 for (size_t i = 0; i < ct.size(); i++) {
159 std::string truncated_ct(ct, 0, i);
160 EXPECT_FALSE(cipher->Decrypt(truncated_ct, associated_data).ok()) << i;
161 }
162 }
163
TEST(AesEaxBoringSslTest,TestInvalidKeySizes)164 TEST(AesEaxBoringSslTest, TestInvalidKeySizes) {
165 if (IsFipsModeEnabled()) {
166 GTEST_SKIP() << "Not supported in FIPS-only mode";
167 }
168
169 size_t nonce_size = 12;
170 for (int keysize = 0; keysize < 65; keysize++) {
171 if (keysize == 16 || keysize == 32) {
172 continue;
173 }
174 util::SecretData key(keysize, 'x');
175 auto cipher = AesEaxBoringSsl::New(key, nonce_size);
176 EXPECT_FALSE(cipher.ok());
177 }
178 }
179
TEST(AesEaxBoringSslTest,TestEmpty)180 TEST(AesEaxBoringSslTest, TestEmpty) {
181 if (IsFipsModeEnabled()) {
182 GTEST_SKIP() << "Not supported in FIPS-only mode";
183 }
184
185 size_t nonce_size = 12;
186 util::SecretData key = util::SecretDataFromStringView(
187 test::HexDecodeOrDie("bedcfb5a011ebc84600fcb296c15af0d"));
188 std::string nonce(test::HexDecodeOrDie("438a547a94ea88dce46c6c85"));
189 // Expected tag is an empty string with an empty tag is encrypted with
190 // the nonce above;
191 std::string tag(test::HexDecodeOrDie("9607977cd7556b1dfedf0c73a35a5197"));
192 std::string ciphertext = nonce + tag;
193 auto res = AesEaxBoringSsl::New(key, nonce_size);
194 EXPECT_TRUE(res.ok()) << res.status();
195 auto cipher = std::move(res.value());
196
197 // Test decryption of the arguments above.
198 std::string empty_string("");
199 absl::string_view empty_string_view("");
200 absl::string_view null_string_view;
201
202 auto pt = cipher->Decrypt(ciphertext, empty_string);
203 EXPECT_TRUE(pt.ok());
204 EXPECT_EQ(0, pt.value().size());
205
206 pt = cipher->Decrypt(ciphertext, empty_string_view);
207 EXPECT_TRUE(pt.ok());
208 EXPECT_EQ(0, pt.value().size());
209
210 pt = cipher->Decrypt(ciphertext, null_string_view);
211 EXPECT_TRUE(pt.ok());
212 EXPECT_EQ(0, pt.value().size());
213
214 // Test encryption.
215 auto ct = cipher->Encrypt(empty_string, empty_string);
216 EXPECT_TRUE(ct.ok());
217 pt = cipher->Decrypt(ct.value(), empty_string);
218 EXPECT_TRUE(pt.ok());
219 EXPECT_EQ(0, pt.value().size());
220
221 ct = cipher->Encrypt(empty_string_view, empty_string_view);
222 EXPECT_TRUE(ct.ok());
223 pt = cipher->Decrypt(ct.value(), empty_string);
224 EXPECT_TRUE(pt.ok());
225 EXPECT_EQ(0, pt.value().size());
226
227 ct = cipher->Encrypt(empty_string_view, empty_string_view);
228 EXPECT_TRUE(ct.ok());
229 pt = cipher->Decrypt(ct.value(), empty_string);
230 EXPECT_TRUE(pt.ok());
231 EXPECT_EQ(0, pt.value().size());
232
233 ct = cipher->Encrypt(null_string_view, null_string_view);
234 EXPECT_TRUE(ct.ok());
235 pt = cipher->Decrypt(ct.value(), empty_string);
236 EXPECT_TRUE(pt.ok());
237 EXPECT_EQ(0, pt.value().size());
238 }
239
GetError()240 static std::string GetError() {
241 auto err = ERR_peek_last_error();
242 // Sometimes there is no error message on the stack.
243 if (err == 0) {
244 return "";
245 }
246 std::string lib(ERR_lib_error_string(err));
247 std::string func(ERR_func_error_string(err));
248 std::string reason(ERR_reason_error_string(err));
249 return lib + ":" + func + ":" + reason;
250 }
251
252 // Test with test vectors from project Wycheproof.
253 // AesEaxBoringSsl does not allow to pass in IVs. Therefore this test
254 // can only test decryption.
255 // Currently AesEaxBoringSsl is restricted to encryption with 12 byte
256 // IVs and 16 byte tags. Therefore it is necessary to skip tests with
257 // other parameter sizes.
WycheproofTest(const rapidjson::Document & root)258 bool WycheproofTest(const rapidjson::Document &root) {
259 int errors = 0;
260 for (const rapidjson::Value& test_group : root["testGroups"].GetArray()) {
261 const size_t iv_size = test_group["ivSize"].GetInt();
262 const size_t key_size = test_group["keySize"].GetInt();
263 const size_t tag_size = test_group["tagSize"].GetInt();
264 if (key_size != 128 && key_size != 256) {
265 // Not supported
266 continue;
267 }
268 if (iv_size != 128 && iv_size != 96) {
269 // Not supported
270 continue;
271 }
272 if (tag_size != 128) {
273 // Not supported
274 continue;
275 }
276 for (const rapidjson::Value& test : test_group["tests"].GetArray()) {
277 std::string comment = test["comment"].GetString();
278 util::SecretData key =
279 util::SecretDataFromStringView(WycheproofUtil::GetBytes(test["key"]));
280 std::string iv = WycheproofUtil::GetBytes(test["iv"]);
281 std::string msg = WycheproofUtil::GetBytes(test["msg"]);
282 std::string ct = WycheproofUtil::GetBytes(test["ct"]);
283 std::string associated_data = WycheproofUtil::GetBytes(test["aad"]);
284 std::string tag = WycheproofUtil::GetBytes(test["tag"]);
285 std::string id = absl::StrCat(test["tcId"].GetInt());
286 std::string expected = test["result"].GetString();
287 auto cipher = std::move(AesEaxBoringSsl::New(key, iv_size / 8).value());
288 auto result = cipher->Decrypt(iv + ct + tag, associated_data);
289 bool success = result.ok();
290 if (success) {
291 std::string decrypted = result.value();
292 if (expected == "invalid") {
293 ADD_FAILURE() << "decrypted invalid ciphertext:" << id;
294 errors++;
295 } else if (msg != decrypted) {
296 ADD_FAILURE() << "Incorrect decryption:" << id;
297 errors++;
298 }
299 } else {
300 if (expected == "valid" || expected == "acceptable") {
301 ADD_FAILURE()
302 << "Could not decrypt test with tcId:" << id
303 << " iv_size:" << iv_size
304 << " tag_size:" << tag_size
305 << " key_size:" << key_size
306 << " error:" << GetError();
307 errors++;
308 }
309 }
310 }
311 }
312 return errors == 0;
313 }
314
TEST(AesEaxBoringSslTest,TestVectors)315 TEST(AesEaxBoringSslTest, TestVectors) {
316 if (IsFipsModeEnabled()) {
317 GTEST_SKIP() << "Not supported in FIPS-only mode";
318 }
319
320 std::unique_ptr<rapidjson::Document> root =
321 WycheproofUtil::ReadTestVectors("aes_eax_test.json");
322 ASSERT_TRUE(WycheproofTest(*root));
323 }
324
TEST(AesEaxBoringSslTest,TestFipsOnly)325 TEST(AesEaxBoringSslTest, TestFipsOnly) {
326 if (!IsFipsModeEnabled()) {
327 GTEST_SKIP() << "Only supported in FIPS-only mode";
328 }
329
330 util::SecretData key128 = util::SecretDataFromStringView(
331 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
332 util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
333 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
334
335 EXPECT_THAT(subtle::AesEaxBoringSsl::New(key128, 16).status(),
336 StatusIs(absl::StatusCode::kInternal));
337 EXPECT_THAT(subtle::AesEaxBoringSsl::New(key256, 16).status(),
338 StatusIs(absl::StatusCode::kInternal));
339 }
340
341 } // namespace
342 } // namespace subtle
343 } // namespace tink
344 } // namespace crypto
345
346