xref: /aosp_15_r20/external/tink/cc/subtle/aes_siv_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_siv_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 "tink/config/tink_fips.h"
27 #include "tink/subtle/wycheproof_util.h"
28 #include "tink/util/secret_data.h"
29 #include "tink/util/statusor.h"
30 #include "tink/util/test_matchers.h"
31 #include "tink/util/test_util.h"
32 
33 namespace crypto {
34 namespace tink {
35 namespace subtle {
36 namespace {
37 
38 using ::crypto::tink::test::StatusIs;
39 
TEST(AesSivBoringSslTest,testCarryComputation)40 TEST(AesSivBoringSslTest, testCarryComputation) {
41   if (IsFipsModeEnabled()) {
42     GTEST_SKIP() << "Not supported in FIPS-only mode";
43   }
44   uint8_t value = 0;
45   for (int i = 0; i < 256; i++) {
46     uint8_t carry = *reinterpret_cast<int8_t*>(&value) >> 7;
47     if (i < 128) {
48       EXPECT_EQ(carry, 0x00);
49     } else {
50       EXPECT_EQ(carry, 0xff);
51     }
52     value++;
53   }
54 }
55 
TEST(AesSivBoringSslTest,testEncryptDecrypt)56 TEST(AesSivBoringSslTest, testEncryptDecrypt) {
57   if (IsFipsModeEnabled()) {
58     GTEST_SKIP() << "Not supported in FIPS-only mode";
59   }
60   util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
61       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
62       "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
63   auto res = AesSivBoringSsl::New(key);
64   EXPECT_TRUE(res.ok()) << res.status();
65   auto cipher = std::move(res.value());
66   std::string associated_data = "Associated data";
67   std::string message = "Some data to encrypt.";
68   auto ct = cipher->EncryptDeterministically(message, associated_data);
69   EXPECT_TRUE(ct.ok()) << ct.status();
70   auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
71   EXPECT_TRUE(pt.ok()) << pt.status();
72   EXPECT_EQ(pt.value(), message);
73 }
74 
TEST(AesSivBoringSslTest,testNullPtrStringView)75 TEST(AesSivBoringSslTest, testNullPtrStringView) {
76   if (IsFipsModeEnabled()) {
77     GTEST_SKIP() << "Not supported in FIPS-only mode";
78   }
79   util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
80       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
81       "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
82   auto res = AesSivBoringSsl::New(key);
83   EXPECT_TRUE(res.ok()) << res.status();
84   // Checks that a default constructed string_view works.
85   auto cipher = std::move(res.value());
86   absl::string_view null;
87   auto ct = cipher->EncryptDeterministically(null, null);
88   EXPECT_TRUE(ct.ok()) << ct.status();
89   auto pt = cipher->DecryptDeterministically(ct.value(), null);
90   EXPECT_TRUE(pt.ok()) << pt.status();
91   EXPECT_EQ("", pt.value());
92   // Decryption with ct == null should return an appropriate status.
93   pt = cipher->DecryptDeterministically(null, "");
94   EXPECT_FALSE(pt.ok());
95   // Associated data with an empty string view is the same an empty string.
96   std::string message("123456789abcdefghijklmnop");
97   ct = cipher->EncryptDeterministically(message, null);
98   pt = cipher->DecryptDeterministically(ct.value(), "");
99   EXPECT_TRUE(pt.ok()) << pt.status();
100   EXPECT_EQ(message, pt.value());
101   ct = cipher->EncryptDeterministically(message, "");
102   pt = cipher->DecryptDeterministically(ct.value(), null);
103   EXPECT_TRUE(pt.ok()) << pt.status();
104   EXPECT_EQ(message, pt.value());
105 }
106 
107 // Only 64 byte key sizes are supported.
TEST(AesSivBoringSslTest,testEncryptDecryptKeySizes)108 TEST(AesSivBoringSslTest, testEncryptDecryptKeySizes) {
109   if (IsFipsModeEnabled()) {
110     GTEST_SKIP() << "Not supported in FIPS-only mode";
111   }
112   util::SecretData keymaterial =
113       util::SecretDataFromStringView(test::HexDecodeOrDie(
114           "198371900187498172316311acf81d238ff7619873a61983d619c87b63a1987f"
115           "987131819803719b847126381cd763871638aa71638176328761287361231321"
116           "812731321de508761437195ff231765aa4913219873ac6918639816312130011"
117           "abc900bba11400187984719827431246bbab1231eb4145215ff7141436616beb"
118           "9817298148712fed3aab61000ff123313e"));
119   for (int keysize = 0; keysize < keymaterial.size(); ++keysize){
120     util::SecretData key(&keymaterial[0], &keymaterial[keysize]);
121     auto cipher = AesSivBoringSsl::New(key);
122     if (keysize == 64) {
123       EXPECT_TRUE(cipher.ok());
124     } else {
125       EXPECT_FALSE(cipher.ok()) << "Accepted invalid key size:" << keysize;
126     }
127   }
128 }
129 
130 // Checks a range of message sizes.
TEST(AesSivBoringSslTest,testEncryptDecryptMessageSize)131 TEST(AesSivBoringSslTest, testEncryptDecryptMessageSize) {
132   if (IsFipsModeEnabled()) {
133     GTEST_SKIP() << "Not supported in FIPS-only mode";
134   }
135   util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
136       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
137       "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
138   auto res = AesSivBoringSsl::New(key);
139   EXPECT_TRUE(res.ok()) << res.status();
140   auto cipher = std::move(res.value());
141   std::string associated_data = "Associated data";
142   for (int i = 0; i < 1024; ++i) {
143     std::string message = std::string(i, 'a');
144     auto ct = cipher->EncryptDeterministically(message, associated_data);
145     EXPECT_TRUE(ct.ok()) << ct.status();
146     auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
147     EXPECT_TRUE(pt.ok()) << pt.status();
148     EXPECT_EQ(pt.value(), message);
149   }
150   for (int i = 1024; i < 100000; i+= 5000) {
151     std::string message = std::string(i, 'a');
152     auto ct = cipher->EncryptDeterministically(message, associated_data);
153     EXPECT_TRUE(ct.ok()) << ct.status();
154     auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
155     EXPECT_TRUE(pt.ok()) << pt.status();
156     EXPECT_EQ(pt.value(), message);
157   }
158 }
159 
160 // Checks a range of associated_data sizes.
TEST(AesSivBoringSslTest,testEncryptDecryptAssociatedDataSize)161 TEST(AesSivBoringSslTest, testEncryptDecryptAssociatedDataSize) {
162   if (IsFipsModeEnabled()) {
163     GTEST_SKIP() << "Not supported in FIPS-only mode";
164   }
165   util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
166       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
167       "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
168   auto res = AesSivBoringSsl::New(key);
169   EXPECT_TRUE(res.ok()) << res.status();
170   auto cipher = std::move(res.value());
171   std::string message = "Some plaintext";
172   for (int i = 0; i < 1028; ++i) {
173     std::string associated_data = std::string(i, 'a');
174     auto ct = cipher->EncryptDeterministically(message, associated_data);
175     EXPECT_TRUE(ct.ok()) << ct.status();
176     auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
177     EXPECT_TRUE(pt.ok()) << pt.status();
178     EXPECT_EQ(pt.value(), message);
179   }
180 }
181 
TEST(AesSivBoringSslTest,testDecryptModification)182 TEST(AesSivBoringSslTest, testDecryptModification) {
183   if (IsFipsModeEnabled()) {
184     GTEST_SKIP() << "Not supported in FIPS-only mode";
185   }
186   util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
187       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
188       "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
189   auto res = AesSivBoringSsl::New(key);
190   EXPECT_TRUE(res.ok()) << res.status();
191   auto cipher = std::move(res.value());
192   std::string associated_data = "Associated data";
193   for (int i = 0; i < 50; ++i) {
194     std::string message = std::string(i, 'a');
195     auto ct = cipher->EncryptDeterministically(message, associated_data);
196     EXPECT_TRUE(ct.ok()) << ct.status();
197     std::string ciphertext = ct.value();
198     for (size_t b = 0; b < ciphertext.size(); ++b) {
199       for (int bit = 0; bit < 8; ++bit) {
200         std::string modified = ciphertext;
201         modified[b] ^= (1 << bit);
202         auto pt = cipher->DecryptDeterministically(modified, associated_data);
203         EXPECT_FALSE(pt.ok())
204             << "Modified ciphertext decrypted."
205             << " byte:" << b
206             << " bit:" << bit;
207       }
208     }
209   }
210 }
211 
212 // Test with test vectors from project Wycheproof.
WycheproofTest(const rapidjson::Document & root)213 void WycheproofTest(const rapidjson::Document &root) {
214   for (const rapidjson::Value& test_group : root["testGroups"].GetArray()) {
215     const size_t key_size = test_group["keySize"].GetInt();
216     if (!AesSivBoringSsl::IsValidKeySizeInBytes(key_size / 8)) {
217       // Currently the key size is restricted to two 256-bit AES keys.
218       continue;
219     }
220     for (const rapidjson::Value& test : test_group["tests"].GetArray()) {
221       std::string comment = test["comment"].GetString();
222       util::SecretData key =
223           util::SecretDataFromStringView(WycheproofUtil::GetBytes(test["key"]));
224       std::string msg = WycheproofUtil::GetBytes(test["msg"]);
225       std::string ct = WycheproofUtil::GetBytes(test["ct"]);
226       std::string associated_data = WycheproofUtil::GetBytes(test["aad"]);
227       int id = test["tcId"].GetInt();
228       std::string result = test["result"].GetString();
229       auto cipher = std::move(AesSivBoringSsl::New(key).value());
230 
231       // Test encryption.
232       // Encryption should always succeed since msg and aad are valid inputs.
233       std::string encrypted =
234           cipher->EncryptDeterministically(msg, associated_data).value();
235       std::string encrypted_hex = test::HexEncode(encrypted);
236       std::string ct_hex = test::HexEncode(ct);
237       if (result == "valid" || result == "acceptable") {
238         EXPECT_EQ(ct_hex, encrypted_hex)
239             << "incorrect encryption: " << id << " " << comment;
240       } else {
241         EXPECT_NE(ct_hex, encrypted_hex)
242             << "invalid encryption: " << id << " " << comment;
243       }
244 
245       // Test decryption
246       auto decrypted = cipher->DecryptDeterministically(ct, associated_data);
247       if (decrypted.ok()) {
248         if (result == "invalid") {
249           ADD_FAILURE() << "decrypted invalid ciphertext:" << id;
250         } else {
251           EXPECT_EQ(test::HexEncode(msg), test::HexEncode(decrypted.value()))
252               << "incorrect decryption: " << id << " " << comment;
253         }
254       } else {
255         EXPECT_NE(result, "valid")
256             << "failed to decrypt: " << id << " " << comment;
257       }
258     }
259   }
260 }
261 
TEST(AesSivBoringSslTest,TestVectors)262 TEST(AesSivBoringSslTest, TestVectors) {
263   if (IsFipsModeEnabled()) {
264     GTEST_SKIP() << "Not supported in FIPS-only mode";
265   }
266   std::unique_ptr<rapidjson::Document> root =
267       WycheproofUtil::ReadTestVectors("aes_siv_cmac_test.json");
268   WycheproofTest(*root);
269 }
270 
TEST(AesEaxBoringSslTest,TestFipsOnly)271 TEST(AesEaxBoringSslTest, TestFipsOnly) {
272   if (!IsFipsModeEnabled()) {
273     GTEST_SKIP() << "Only supported in FIPS-only mode";
274   }
275 
276   util::SecretData key128 = util::SecretDataFromStringView(
277       test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
278   util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
279       "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
280 
281   EXPECT_THAT(subtle::AesSivBoringSsl::New(key128).status(),
282               StatusIs(absl::StatusCode::kInternal));
283   EXPECT_THAT(subtle::AesSivBoringSsl::New(key256).status(),
284               StatusIs(absl::StatusCode::kInternal));
285 }
286 
287 }  // namespace
288 }  // namespace subtle
289 }  // namespace tink
290 }  // namespace crypto
291