xref: /aosp_15_r20/external/tink/cc/subtle/aes_eax_boringssl_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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