1 // Copyright 2021 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 #include "tink/aead/internal/ssl_aead.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <iostream>
21 #include <iterator>
22 #include <limits>
23 #include <memory>
24 #include <string>
25 #include <unordered_set>
26 #include <vector>
27
28 #include "gmock/gmock.h"
29 #include "gtest/gtest.h"
30 #include "absl/container/flat_hash_set.h"
31 #include "absl/status/status.h"
32 #include "absl/strings/escaping.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/string_view.h"
35 #include "absl/types/span.h"
36 #include "tink/aead/internal/wycheproof_aead.h"
37 #include "tink/internal/fips_utils.h"
38 #include "tink/internal/ssl_util.h"
39 #include "tink/subtle/subtle_util.h"
40 #include "tink/util/secret_data.h"
41 #include "tink/util/statusor.h"
42 #include "tink/util/test_matchers.h"
43
44 namespace crypto {
45 namespace tink {
46 namespace internal {
47 namespace {
48
49 using ::crypto::tink::test::IsOk;
50 using ::crypto::tink::test::StatusIs;
51 using ::testing::AllOf;
52 using ::testing::Eq;
53 using ::testing::Not;
54 using ::testing::TestParamInfo;
55 using ::testing::TestWithParam;
56 using ::testing::ValuesIn;
57
58 constexpr absl::string_view kMessage = "Some data to encrypt.";
59 constexpr absl::string_view kAssociatedData = "Some associated data.";
60 // 128 bits key.
61 constexpr absl::string_view k128Key = "000102030405060708090a0b0c0d0e0f";
62 // 256 bits key.
63 constexpr absl::string_view k256Key =
64 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f";
65 // 12 bytes IV.
66 constexpr absl::string_view kAesGcmIvHex = "0123456789012345678901234";
67 // 24 bytes IV.
68 constexpr absl::string_view kXchacha20Poly1305IvHex =
69 "012345678901234567890123456789012345678901234567";
70
71 enum CipherType {
72 kAesGcm,
73 kAesGcmSiv,
74 kXchacha20Poly1305,
75 };
76
77 struct SslOneShotAeadTestParams {
78 std::string test_name;
79 CipherType cipher;
80 int tag_size;
81 absl::string_view iv_hex;
82 absl::string_view key_hex;
83 };
84
85 // Returns a SslOneShotAead from `cipher_name` and `key`.
CipherFromName(CipherType cipher,const util::SecretData & key)86 util::StatusOr<std::unique_ptr<SslOneShotAead>> CipherFromName(
87 CipherType cipher, const util::SecretData& key) {
88 switch (cipher) {
89 case CipherType::kAesGcm: {
90 return CreateAesGcmOneShotCrypter(key);
91 }
92 case CipherType::kAesGcmSiv: {
93 return CreateAesGcmSivOneShotCrypter(key);
94 }
95 case CipherType::kXchacha20Poly1305: {
96 return CreateXchacha20Poly1305OneShotCrypter(key);
97 }
98 }
99 }
100
101 using SslOneShotAeadTest = TestWithParam<SslOneShotAeadTestParams>;
102
TEST_P(SslOneShotAeadTest,CiphertextPlaintextSize)103 TEST_P(SslOneShotAeadTest, CiphertextPlaintextSize) {
104 SslOneShotAeadTestParams test_param = GetParam();
105 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
106 test_param.cipher, util::SecretDataFromStringView(
107 absl::HexStringToBytes(test_param.key_hex)));
108 ASSERT_THAT(aead, IsOk());
109
110 EXPECT_EQ((*aead)->CiphertextSize(kMessage.size()),
111 kMessage.size() + test_param.tag_size);
112 EXPECT_EQ((*aead)->PlaintextSize(kMessage.size() + test_param.tag_size),
113 kMessage.size());
114 // Minimum size.
115 EXPECT_EQ((*aead)->PlaintextSize(test_param.tag_size), 0);
116 // Smaller than the minumum.
117 EXPECT_EQ((*aead)->PlaintextSize(0), 0);
118 }
119
120 // Tests that encryption of `message` with `associated_data`, and `iv` succeeds;
121 // writes the result in `ciphertext_buffer`.
DoTestEncrypt(SslOneShotAead * aead,absl::string_view message,absl::string_view associated_data,size_t tag_size,absl::string_view iv,absl::Span<char> ciphertext_buffer)122 void DoTestEncrypt(SslOneShotAead* aead, absl::string_view message,
123 absl::string_view associated_data, size_t tag_size,
124 absl::string_view iv, absl::Span<char> ciphertext_buffer) {
125 ASSERT_GE(ciphertext_buffer.size(), message.size() + tag_size);
126 util::StatusOr<int64_t> res = aead->Encrypt(
127 message, associated_data, iv, absl::MakeSpan(ciphertext_buffer));
128 ASSERT_THAT(res, IsOk());
129 EXPECT_EQ(*res, message.size() + tag_size);
130 }
131
132 // Tests that decryption of `ciphertext_buffer` with `associated_data` and `iv`
133 // succeeds and equals `message`.
DoTestDecrypt(SslOneShotAead * aead,absl::string_view message,absl::string_view associated_data,absl::string_view iv,absl::string_view ciphertext_buffer)134 void DoTestDecrypt(SslOneShotAead* aead, absl::string_view message,
135 absl::string_view associated_data, absl::string_view iv,
136 absl::string_view ciphertext_buffer) {
137 std::string plaintext_buff;
138 subtle::ResizeStringUninitialized(&plaintext_buff, message.size());
139 util::StatusOr<int64_t> written_bytes = aead->Decrypt(
140 ciphertext_buffer, associated_data, iv, absl::MakeSpan(plaintext_buff));
141 ASSERT_THAT(written_bytes, IsOk());
142 EXPECT_EQ(*written_bytes, message.size());
143 EXPECT_EQ(plaintext_buff, message);
144 }
145
TEST_P(SslOneShotAeadTest,EncryptDecrypt)146 TEST_P(SslOneShotAeadTest, EncryptDecrypt) {
147 SslOneShotAeadTestParams test_param = GetParam();
148 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
149 test_param.cipher, util::SecretDataFromStringView(
150 absl::HexStringToBytes(test_param.key_hex)));
151 ASSERT_THAT(aead, IsOk());
152
153 std::string iv = absl::HexStringToBytes(test_param.iv_hex);
154 std::string ciphertext_buffer;
155 // Length of the message + tag.
156 subtle::ResizeStringUninitialized(&ciphertext_buffer,
157 (*aead)->CiphertextSize(kMessage.size()));
158 DoTestEncrypt(aead->get(), kMessage, kAssociatedData, test_param.tag_size, iv,
159 absl::MakeSpan(ciphertext_buffer));
160 DoTestDecrypt(aead->get(), kMessage, kAssociatedData, iv, ciphertext_buffer);
161 }
162
163 // Calculates a new string with the `position`'s byte modified.
ModifyString(absl::string_view input_str,int position)164 std::string ModifyString(absl::string_view input_str, int position) {
165 std::string modified(input_str.data(), input_str.size());
166 modified[position / 8] ^= 1 << (position % 8);
167 return modified;
168 }
169
170 // Tests encryption/decryption with a modified ciphertext.
DoTestEncryptDecryptWithModifiedCiphertext(SslOneShotAead * aead,size_t tag_size,absl::string_view iv)171 void DoTestEncryptDecryptWithModifiedCiphertext(SslOneShotAead* aead,
172 size_t tag_size,
173 absl::string_view iv) {
174 std::string ciphertext_buffer;
175 // Length of the message + tag.
176 subtle::ResizeStringUninitialized(&ciphertext_buffer,
177 kMessage.size() + tag_size);
178
179 util::StatusOr<int64_t> written_bytes = aead->Encrypt(
180 kMessage, kAssociatedData, iv, absl::MakeSpan(ciphertext_buffer));
181 ASSERT_THAT(written_bytes, IsOk());
182 EXPECT_EQ(*written_bytes, kMessage.size() + tag_size);
183 std::string plaintext_buffer;
184 subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size());
185
186 // Modify the ciphertext.
187 for (size_t i = 0; i < ciphertext_buffer.size() * 8; i++) {
188 EXPECT_THAT(
189 aead->Decrypt(ModifyString(ciphertext_buffer, i), kAssociatedData, iv,
190 absl::MakeSpan(plaintext_buffer))
191 .status(),
192 Not(IsOk()))
193 << i;
194 }
195 // Modify the associated data.
196 for (size_t i = 0; i < kAssociatedData.size() * 8; i++) {
197 EXPECT_THAT(
198 aead->Decrypt(ciphertext_buffer, ModifyString(kAssociatedData, i), iv,
199 absl::MakeSpan(plaintext_buffer))
200 .status(),
201 Not(IsOk()))
202 << i;
203 }
204 // Truncate the ciphertext.
205 for (size_t i = 0; i < ciphertext_buffer.size(); i++) {
206 std::string truncated_ct(ciphertext_buffer, 0, i);
207 EXPECT_THAT(aead->Decrypt(truncated_ct, kAssociatedData, iv,
208 absl::MakeSpan(plaintext_buffer))
209 .status(),
210 Not(IsOk()))
211 << i;
212 }
213 }
214
TEST_P(SslOneShotAeadTest,TestModification)215 TEST_P(SslOneShotAeadTest, TestModification) {
216 if (IsFipsModeEnabled()) {
217 GTEST_SKIP() << "Not supported in FIPS-only mode";
218 }
219
220 SslOneShotAeadTestParams test_param = GetParam();
221 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
222 test_param.cipher, util::SecretDataFromStringView(
223 absl::HexStringToBytes(test_param.key_hex)));
224 ASSERT_THAT(aead, IsOk());
225
226 DoTestEncryptDecryptWithModifiedCiphertext(
227 aead->get(), test_param.tag_size,
228 absl::HexStringToBytes(test_param.iv_hex));
229 }
230
231 // Make sure that the buffer passed in to the Decrypt routine is cleared if
232 // decryption fails.
TEST_P(SslOneShotAeadTest,TestBufferClearsIfDecryptionFails)233 TEST_P(SslOneShotAeadTest, TestBufferClearsIfDecryptionFails) {
234 if (IsFipsModeEnabled()) {
235 GTEST_SKIP() << "Not supported in FIPS-only mode";
236 }
237
238 SslOneShotAeadTestParams test_param = GetParam();
239 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
240 test_param.cipher, util::SecretDataFromStringView(
241 absl::HexStringToBytes(test_param.key_hex)));
242 ASSERT_THAT(aead, IsOk());
243
244 const int64_t kCiphertextSize = kMessage.size() + test_param.tag_size;
245 std::string ciphertext_buffer;
246 // Length of the message + tag.
247 subtle::ResizeStringUninitialized(&ciphertext_buffer, kCiphertextSize);
248 std::string iv = absl::HexStringToBytes(test_param.iv_hex);
249 util::StatusOr<int64_t> written_bytes = (*aead)->Encrypt(
250 kMessage, kAssociatedData, iv, absl::MakeSpan(ciphertext_buffer));
251 ASSERT_THAT(written_bytes, IsOk());
252 EXPECT_EQ(*written_bytes, kCiphertextSize);
253
254 std::string plaintext_buffer;
255 subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size());
256 const std::string kExpectedClearedPlaintext(plaintext_buffer.size(), '\0');
257 // Alter the tag.
258 for (int i = kCiphertextSize - test_param.tag_size; i < kCiphertextSize;
259 i++) {
260 std::string modified_ciphertext = ModifyString(ciphertext_buffer, i);
261 EXPECT_THAT((*aead)
262 ->Decrypt(modified_ciphertext, kAssociatedData, iv,
263 absl::MakeSpan(plaintext_buffer))
264 .status(),
265 Not(IsOk()));
266 EXPECT_EQ(plaintext_buffer, kExpectedClearedPlaintext);
267 }
268 }
269
TestDecryptWithEmptyAssociatedData(SslOneShotAead * aead,absl::string_view ciphertext,absl::string_view iv)270 void TestDecryptWithEmptyAssociatedData(SslOneShotAead* aead,
271 absl::string_view ciphertext,
272 absl::string_view iv) {
273 if (IsFipsModeEnabled()) {
274 GTEST_SKIP() << "Not supported in FIPS-only mode";
275 }
276 std::string plaintext_buffer;
277 subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size());
278 const absl::string_view empty_associated_data;
279 std::vector<absl::string_view> values = {empty_associated_data,
280 absl::string_view(), ""};
281 for (auto& associated_data : values) {
282 DoTestDecrypt(aead, kMessage, associated_data, iv, ciphertext);
283 }
284 }
285
DoTestWithEmptyAssociatedData(SslOneShotAead * aead,absl::string_view iv,size_t tag_size)286 void DoTestWithEmptyAssociatedData(SslOneShotAead* aead, absl::string_view iv,
287 size_t tag_size) {
288 const absl::string_view empty_associated_data;
289 std::vector<absl::string_view> values = {empty_associated_data,
290 absl::string_view(), ""};
291 for (auto& associated_data : values) {
292 std::string ciphertext_buffer;
293 subtle::ResizeStringUninitialized(&ciphertext_buffer,
294 kMessage.size() + tag_size);
295 DoTestEncrypt(aead, kMessage, associated_data, tag_size, iv,
296 absl::MakeSpan(ciphertext_buffer));
297 TestDecryptWithEmptyAssociatedData(aead, ciphertext_buffer, iv);
298 }
299 }
300
TEST_P(SslOneShotAeadTest,EmptyAssociatedData)301 TEST_P(SslOneShotAeadTest, EmptyAssociatedData) {
302 if (IsFipsModeEnabled()) {
303 GTEST_SKIP() << "Not supported in FIPS-only mode";
304 }
305 SslOneShotAeadTestParams test_param = GetParam();
306 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
307 test_param.cipher, util::SecretDataFromStringView(
308 absl::HexStringToBytes(test_param.key_hex)));
309 ASSERT_THAT(aead, IsOk());
310 DoTestWithEmptyAssociatedData(aead->get(),
311 absl::HexStringToBytes(test_param.iv_hex),
312 test_param.tag_size);
313 }
314
315 // string_views, with `iv` and `associated_data`.
DoTestEmptyMessageEncryptDecrypt(SslOneShotAead * aead,absl::string_view iv,size_t tag_size,absl::string_view associated_data=kAssociatedData)316 void DoTestEmptyMessageEncryptDecrypt(
317 SslOneShotAead* aead, absl::string_view iv, size_t tag_size,
318 absl::string_view associated_data = kAssociatedData) {
319 std::string ciphertext_buffer;
320 subtle::ResizeStringUninitialized(&ciphertext_buffer, tag_size);
321 { // Message is a null string_view.
322 const absl::string_view message;
323 DoTestEncrypt(aead, message, associated_data, tag_size, iv,
324 absl::MakeSpan(ciphertext_buffer));
325 DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer);
326 }
327 { // Message is an empty string.
328 const std::string message = "";
329 DoTestEncrypt(aead, message, associated_data, tag_size, iv,
330 absl::MakeSpan(ciphertext_buffer));
331 DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer);
332 }
333 { // Message is a default-constructed string_view.
334 DoTestEncrypt(aead, absl::string_view(), associated_data, tag_size, iv,
335 absl::MakeSpan(ciphertext_buffer));
336 DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer);
337 }
338 }
339
TEST_P(SslOneShotAeadTest,EmptyMessage)340 TEST_P(SslOneShotAeadTest, EmptyMessage) {
341 if (IsFipsModeEnabled()) {
342 GTEST_SKIP() << "Not supported in FIPS-only mode";
343 }
344 SslOneShotAeadTestParams test_param = GetParam();
345 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
346 test_param.cipher, util::SecretDataFromStringView(
347 absl::HexStringToBytes(test_param.key_hex)));
348 ASSERT_THAT(aead, IsOk());
349 std::string iv = absl::HexStringToBytes(test_param.iv_hex);
350 DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size);
351 }
352
TEST_P(SslOneShotAeadTest,EmptyMessageAndAssociatedData)353 TEST_P(SslOneShotAeadTest, EmptyMessageAndAssociatedData) {
354 if (IsFipsModeEnabled()) {
355 GTEST_SKIP() << "Not supported in FIPS-only mode";
356 }
357 SslOneShotAeadTestParams test_param = GetParam();
358 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
359 test_param.cipher, util::SecretDataFromStringView(
360 absl::HexStringToBytes(test_param.key_hex)));
361 ASSERT_THAT(aead, IsOk());
362 std::string iv = absl::HexStringToBytes(test_param.iv_hex);
363 const absl::string_view default_associated_data;
364 const absl::string_view empty_associated_data = "";
365 DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size,
366 default_associated_data);
367 DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size,
368 /*associated_data=*/absl::string_view());
369 DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size,
370 empty_associated_data);
371 }
372
TEST_P(SslOneShotAeadTest,BufferOverlapEncryptFails)373 TEST_P(SslOneShotAeadTest, BufferOverlapEncryptFails) {
374 SslOneShotAeadTestParams test_param = GetParam();
375 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
376 test_param.cipher, util::SecretDataFromStringView(
377 absl::HexStringToBytes(test_param.key_hex)));
378 ASSERT_THAT(aead, IsOk());
379
380 std::string ciphertext_buffer(kMessage.data(), kMessage.size());
381 subtle::ResizeStringUninitialized(&ciphertext_buffer,
382 (*aead)->CiphertextSize(kMessage.size()));
383
384 EXPECT_THAT(
385 (*aead)
386 ->Encrypt(
387 absl::string_view(ciphertext_buffer).substr(0, kMessage.size()),
388 kAssociatedData, test_param.iv_hex,
389 absl::MakeSpan(ciphertext_buffer))
390 .status(),
391 StatusIs(absl::StatusCode::kInvalidArgument));
392 }
393
TEST_P(SslOneShotAeadTest,BufferOverlapDecryptFails)394 TEST_P(SslOneShotAeadTest, BufferOverlapDecryptFails) {
395 SslOneShotAeadTestParams test_param = GetParam();
396 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead = CipherFromName(
397 test_param.cipher, util::SecretDataFromStringView(
398 absl::HexStringToBytes(test_param.key_hex)));
399 ASSERT_THAT(aead, IsOk());
400
401 std::string iv = absl::HexStringToBytes(test_param.iv_hex);
402 std::string ciphertext_buffer;
403 // Length of the message + tag.
404 subtle::ResizeStringUninitialized(&ciphertext_buffer,
405 (*aead)->CiphertextSize(kMessage.size()));
406 DoTestEncrypt(aead->get(), kMessage, kAssociatedData, test_param.tag_size, iv,
407 absl::MakeSpan(ciphertext_buffer));
408
409 EXPECT_THAT(
410 (*aead)
411 ->Decrypt(
412 ciphertext_buffer, kAssociatedData, iv,
413 absl::MakeSpan(ciphertext_buffer).subspan(0, kMessage.size()))
414 .status(),
415 StatusIs(absl::StatusCode::kInvalidArgument));
416 }
417
GetSslOneShotAeadTestParams()418 std::vector<SslOneShotAeadTestParams> GetSslOneShotAeadTestParams() {
419 std::vector<SslOneShotAeadTestParams> params = {
420 {/*test_name=*/"AesGcm256", /*cipher=*/CipherType::kAesGcm,
421 /*tag_size=*/kAesGcmTagSizeInBytes,
422 /*iv_hex=*/kAesGcmIvHex,
423 /*key_hex=*/k256Key},
424 {/*test_name=*/"AesGcm128", /*cipher=*/CipherType::kAesGcm,
425 /*tag_size=*/kAesGcmTagSizeInBytes,
426 /*iv_hex=*/kAesGcmIvHex,
427 /*key_hex=*/k128Key}};
428 if (IsBoringSsl()) {
429 params.push_back({/*test_name=*/"AesGcmSiv256",
430 /*cipher=*/CipherType::kAesGcmSiv,
431 /*tag_size=*/kAesGcmTagSizeInBytes,
432 /*iv_hex=*/kAesGcmIvHex,
433 /*key_hex=*/k256Key});
434 params.push_back({/*test_name=*/"AesGcmSiv128",
435 /*cipher=*/CipherType::kAesGcmSiv,
436 /*tag_size=*/kAesGcmTagSizeInBytes,
437 /*iv_hex=*/kAesGcmIvHex,
438 /*key_hex=*/k128Key});
439 params.push_back({/*test_name=*/"Xchacha20Poly1305",
440 /*cipher=*/CipherType::kXchacha20Poly1305,
441 /*tag_size=*/kXchacha20Poly1305TagSizeInBytes,
442 /*iv_hex=*/kXchacha20Poly1305IvHex,
443 /*key_hex=*/k256Key});
444 }
445 return params;
446 }
447
448 INSTANTIATE_TEST_SUITE_P(
449 SslOneShotAeadTests, SslOneShotAeadTest,
450 testing::ValuesIn(GetSslOneShotAeadTestParams()),
__anond5b904b60202(const TestParamInfo<SslOneShotAeadTest::ParamType>& info) 451 [](const TestParamInfo<SslOneShotAeadTest::ParamType>& info) {
452 return info.param.test_name;
453 });
454
TEST(SslOneShotAeadTest,AesGcmTestInvalidKeySizes)455 TEST(SslOneShotAeadTest, AesGcmTestInvalidKeySizes) {
456 if (IsFipsModeEnabled()) {
457 GTEST_SKIP() << "Not supported in FIPS-only mode";
458 }
459
460 for (int keysize = 0; keysize < 65; keysize++) {
461 util::SecretData key(keysize, 'x');
462 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
463 CreateAesGcmOneShotCrypter(key);
464 if (keysize == 16 || keysize == 32) {
465 EXPECT_THAT(aead, IsOk()) << "with key size " << keysize;
466 } else {
467 EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize;
468 }
469 }
470 }
471
TEST(SslOneShotAeadTest,AesGcmSivTestInvalidKeySizes)472 TEST(SslOneShotAeadTest, AesGcmSivTestInvalidKeySizes) {
473 if (!IsBoringSsl()) {
474 GTEST_SKIP() << "AES-GCM-SIV not supported with OpenSSL";
475 }
476 if (IsFipsModeEnabled()) {
477 GTEST_SKIP() << "Not supported in FIPS-only mode";
478 }
479
480 for (int keysize = 0; keysize < 65; keysize++) {
481 util::SecretData key(keysize, 'x');
482 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
483 CreateAesGcmSivOneShotCrypter(key);
484 if (keysize == 16 || keysize == 32) {
485 EXPECT_THAT(aead, IsOk()) << "with key size " << keysize;
486 } else {
487 EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize;
488 }
489 }
490 }
491
TEST(SslOneShotAeadTest,Xchacha20Poly1305TestInvalidKeySizes)492 TEST(SslOneShotAeadTest, Xchacha20Poly1305TestInvalidKeySizes) {
493 if (!IsBoringSsl()) {
494 GTEST_SKIP() << "Xchacha20-Poly1305 not supported with OpenSSL";
495 }
496 if (IsFipsModeEnabled()) {
497 GTEST_SKIP() << "Not supported in FIPS-only mode";
498 }
499
500 for (int keysize = 0; keysize < 65; keysize++) {
501 util::SecretData key(keysize, 'x');
502 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
503 CreateXchacha20Poly1305OneShotCrypter(key);
504 if (keysize == 32) {
505 EXPECT_THAT(aead, IsOk()) << "with key size " << keysize;
506 } else {
507 EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize;
508 }
509 }
510 }
511
TEST(SslOneShotAeadTest,Xchacha20Poly1305TestFipsOnly)512 TEST(SslOneShotAeadTest, Xchacha20Poly1305TestFipsOnly) {
513 if (!IsBoringSsl()) {
514 GTEST_SKIP() << "Xchacha20-Poly1305 not supported with OpenSSL";
515 }
516 if (!IsFipsModeEnabled()) {
517 GTEST_SKIP() << "Only supported in FIPS-only mode";
518 }
519
520 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
521 CreateXchacha20Poly1305OneShotCrypter(
522 util::SecretDataFromStringView(absl::HexStringToBytes(k256Key)));
523 EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInternal));
524 }
525
TEST(SslOneShotAeadTest,AesGcmTestFipsOnly)526 TEST(SslOneShotAeadTest, AesGcmTestFipsOnly) {
527 if (IsFipsModeEnabled() && !IsFipsEnabledInSsl()) {
528 GTEST_SKIP() << "Test should not run in FIPS mode when BoringCrypto is "
529 "unavailable.";
530 }
531
532 util::SecretData key_128 =
533 util::SecretDataFromStringView(absl::HexStringToBytes(k128Key));
534 util::SecretData key_256 =
535 util::SecretDataFromStringView(absl::HexStringToBytes(k256Key));
536
537 EXPECT_THAT(CreateAesGcmOneShotCrypter(key_128), IsOk());
538 EXPECT_THAT(CreateAesGcmOneShotCrypter(key_256), IsOk());
539 }
540
TEST(SslOneShotAeadTest,AesGcmTestTestFipsFailWithoutBoringCrypto)541 TEST(SslOneShotAeadTest, AesGcmTestTestFipsFailWithoutBoringCrypto) {
542 if (!IsFipsModeEnabled() || IsFipsEnabledInSsl()) {
543 GTEST_SKIP()
544 << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
545 }
546
547 util::SecretData key_128 =
548 util::SecretDataFromStringView(absl::HexStringToBytes(k128Key));
549 util::SecretData key_256 =
550 util::SecretDataFromStringView(absl::HexStringToBytes(k256Key));
551
552 EXPECT_THAT(CreateAesGcmOneShotCrypter(key_128).status(),
553 StatusIs(absl::StatusCode::kInternal));
554 EXPECT_THAT(CreateAesGcmOneShotCrypter(key_256).status(),
555 StatusIs(absl::StatusCode::kInternal));
556 }
557
TEST(AesGcmSivBoringSslTest,AesGcmTestSivTestFipsOnly)558 TEST(AesGcmSivBoringSslTest, AesGcmTestSivTestFipsOnly) {
559 if (!IsFipsModeEnabled()) {
560 GTEST_SKIP() << "Only supported in FIPS-only mode";
561 }
562
563 util::SecretData key_128 =
564 util::SecretDataFromStringView(absl::HexStringToBytes(k128Key));
565 util::SecretData key_256 =
566 util::SecretDataFromStringView(absl::HexStringToBytes(k256Key));
567
568 EXPECT_THAT(CreateAesGcmSivOneShotCrypter(key_128).status(),
569 StatusIs(absl::StatusCode::kInternal));
570 EXPECT_THAT(CreateAesGcmSivOneShotCrypter(key_256).status(),
571 StatusIs(absl::StatusCode::kInternal));
572 }
573
574 // Parameters for SslOneShotAeadWycheproofTest.
575 struct SslOneShotAeadWycheproofTestParams {
576 std::string test_name;
577 CipherType cipher;
578 int nonce_size;
579 int tag_size;
580 absl::flat_hash_set<int> key_sizes;
581 WycheproofTestVector test_vector;
582 };
583
584 class SslOneShotAeadWycheproofTest
585 : public TestWithParam<SslOneShotAeadWycheproofTestParams> {
586 public:
SetUp()587 void SetUp() override {
588 if (IsFipsModeEnabled()) {
589 GTEST_SKIP() << "Not supported in FIPS-only mode";
590 }
591 SslOneShotAeadWycheproofTestParams params = GetParam();
592 const WycheproofTestVector& test_vector = params.test_vector;
593
594 if (!params.key_sizes.contains(test_vector.key.size()) ||
595 test_vector.nonce.size() != params.nonce_size ||
596 test_vector.tag.size() != params.tag_size) {
597 GTEST_SKIP() << "Unsupported parameters; key size: "
598 << test_vector.key.size()
599 << " nonce size: " << test_vector.nonce.size()
600 << " tag size: " << test_vector.tag.size();
601 }
602 }
603 };
604
TEST_P(SslOneShotAeadWycheproofTest,Encrypt)605 TEST_P(SslOneShotAeadWycheproofTest, Encrypt) {
606 SslOneShotAeadWycheproofTestParams params = GetParam();
607 const WycheproofTestVector& test_vector = params.test_vector;
608 util::SecretData key = util::SecretDataFromStringView(test_vector.key);
609 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
610 CipherFromName(params.cipher, key);
611 ASSERT_THAT(aead, IsOk());
612 std::string ciphertext_and_tag =
613 absl::StrCat(test_vector.ct, test_vector.tag);
614 std::string ciphertext_buffer;
615 subtle::ResizeStringUninitialized(
616 &ciphertext_buffer, (*aead)->CiphertextSize(test_vector.msg.size()));
617 util::StatusOr<int64_t> written_bytes =
618 (*aead)->Encrypt(test_vector.msg, test_vector.aad, test_vector.nonce,
619 absl::MakeSpan(ciphertext_buffer));
620
621 std::string expected_ciphertext =
622 absl::StrCat(test_vector.ct, test_vector.tag);
623
624 std::cout << test_vector.expected << "\n";
625
626 if (test_vector.expected == "valid" || test_vector.expected == "acceptable") {
627 ASSERT_THAT(written_bytes, IsOk());
628 EXPECT_EQ(ciphertext_buffer, expected_ciphertext);
629 } else { // invalid.
630 // In this case, if the resulting ciphertext/tag are different, the
631 // testcase is correct.
632 if (written_bytes.ok()) {
633 EXPECT_THAT(ciphertext_buffer, Not(Eq(expected_ciphertext)));
634 } else {
635 GTEST_SUCCEED();
636 }
637 }
638 }
639
TEST_P(SslOneShotAeadWycheproofTest,Decrypt)640 TEST_P(SslOneShotAeadWycheproofTest, Decrypt) {
641 SslOneShotAeadWycheproofTestParams params = GetParam();
642 const WycheproofTestVector& test_vector = params.test_vector;
643 util::SecretData key = util::SecretDataFromStringView(test_vector.key);
644 util::StatusOr<std::unique_ptr<SslOneShotAead>> aead =
645 CipherFromName(params.cipher, key);
646 ASSERT_THAT(aead, IsOk());
647 std::string ciphertext_and_tag =
648 absl::StrCat(test_vector.ct, test_vector.tag);
649 std::string plaintext_buffer;
650 subtle::ResizeStringUninitialized(
651 &plaintext_buffer, (*aead)->PlaintextSize(ciphertext_and_tag.size()));
652 util::StatusOr<int64_t> written_bytes = (*aead)->Decrypt(
653 absl::StrCat(test_vector.ct, test_vector.tag), test_vector.aad,
654 test_vector.nonce, absl::MakeSpan(plaintext_buffer));
655
656 if (written_bytes.ok()) {
657 EXPECT_NE(test_vector.expected, "invalid");
658 EXPECT_EQ(plaintext_buffer, test_vector.msg);
659 } else {
660 EXPECT_THAT(test_vector.expected, Not(AllOf(Eq("valid"), Eq("acceptable"))))
661 << "Could not decrypt valid/acceptable tId: " << test_vector.id
662 << " iv_size: " << test_vector.nonce.size()
663 << " tag_size: " << test_vector.tag.size()
664 << " key_size: " << key.size() << "; error: " << written_bytes.status();
665 }
666 }
667
GetWycheproofTestParams()668 std::vector<SslOneShotAeadWycheproofTestParams> GetWycheproofTestParams() {
669 std::vector<SslOneShotAeadWycheproofTestParams> params;
670 for (const WycheproofTestVector& test_vector :
671 ReadWycheproofTestVectors("aes_gcm_test.json")) {
672 params.push_back({/*test_name=*/"AesGcm",
673 /*cipher_name=*/CipherType::kAesGcm,
674 /*nonce_size=*/12,
675 /*tag_size=*/16,
676 /*key_sizes=*/{16, 32}, test_vector});
677 }
678 if (IsBoringSsl()) {
679 for (const WycheproofTestVector& test_vector :
680 ReadWycheproofTestVectors("aes_gcm_siv_test.json")) {
681 params.push_back({/*test_name=*/"AesGcmSiv",
682 /*cipher_name=*/CipherType::kAesGcmSiv,
683 /*nonce_size=*/12,
684 /*tag_size=*/16,
685 /*key_sizes=*/{16, 32}, test_vector});
686 }
687 for (const WycheproofTestVector& test_vector :
688 ReadWycheproofTestVectors("xchacha20_poly1305_test.json")) {
689 params.push_back({/*test_name=*/"Xchacha20Poly1305",
690 /*cipher_name=*/CipherType::kXchacha20Poly1305,
691 /*nonce_size=*/24,
692 /*tag_size=*/16,
693 /*key_sizes=*/{32}, test_vector});
694 }
695 }
696 return params;
697 }
698
699 INSTANTIATE_TEST_SUITE_P(
700 SslOneShotAeadWycheproofTests, SslOneShotAeadWycheproofTest,
701 ValuesIn(GetWycheproofTestParams()),
__anond5b904b60302(const TestParamInfo<SslOneShotAeadWycheproofTest::ParamType>& info) 702 [](const TestParamInfo<SslOneShotAeadWycheproofTest::ParamType>& info) {
703 return absl::StrCat(info.param.test_name, "Tid",
704 info.param.test_vector.id);
705 });
706
707 } // namespace
708 } // namespace internal
709 } // namespace tink
710 } // namespace crypto
711