xref: /aosp_15_r20/external/tink/cc/subtle/aes_gcm_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_gcm_boringssl.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/escaping.h"
28 #include "absl/strings/str_cat.h"
29 #include "tink/aead/internal/wycheproof_aead.h"
30 #include "tink/internal/fips_utils.h"
31 #include "tink/util/secret_data.h"
32 #include "tink/util/statusor.h"
33 #include "tink/util/test_matchers.h"
34 
35 namespace crypto {
36 namespace tink {
37 namespace subtle {
38 namespace {
39 
40 constexpr absl::string_view kMessage = "Some data to encrypt.";
41 constexpr absl::string_view kAssociatedData = "Some associated data.";
42 constexpr absl::string_view kKey128 = "000102030405060708090a0b0c0d0e0f";
43 constexpr absl::string_view kKey256 =
44     "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f";
45 
46 using ::crypto::tink::test::IsOk;
47 using ::crypto::tink::test::StatusIs;
48 using ::testing::AllOf;
49 using ::testing::Eq;
50 using ::testing::Not;
51 using ::testing::Test;
52 using ::testing::TestWithParam;
53 using ::testing::ValuesIn;
54 
55 class AesGcmBoringSslTest : public Test {
56  protected:
SetUp()57   void SetUp() override {
58     if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
59       GTEST_SKIP() << "Test should not run in FIPS mode when BoringCrypto is "
60                       "unavailable.";
61     }
62 
63     util::SecretData key =
64         util::SecretDataFromStringView(absl::HexStringToBytes(kKey128));
65     util::StatusOr<std::unique_ptr<Aead>> cipher = AesGcmBoringSsl::New(key);
66     ASSERT_THAT(cipher, IsOk());
67     cipher_ = std::move(*cipher);
68   }
69   std::unique_ptr<Aead> cipher_;
70 };
71 
TEST_F(AesGcmBoringSslTest,BasicEncryptDecrypt)72 TEST_F(AesGcmBoringSslTest, BasicEncryptDecrypt) {
73   util::StatusOr<std::string> ciphertext =
74       cipher_->Encrypt(kMessage, kAssociatedData);
75   ASSERT_THAT(ciphertext, IsOk());
76   EXPECT_EQ(ciphertext->size(), kMessage.size() + 12 + 16);
77   util::StatusOr<std::string> plaintext =
78       cipher_->Decrypt(*ciphertext, kAssociatedData);
79   ASSERT_THAT(plaintext, IsOk());
80   EXPECT_EQ(*plaintext, kMessage);
81 }
82 
TEST_F(AesGcmBoringSslTest,ModifyMessageAndAssociatedData)83 TEST_F(AesGcmBoringSslTest, ModifyMessageAndAssociatedData) {
84   util::StatusOr<std::string> ciphertext =
85       cipher_->Encrypt(kMessage, kAssociatedData);
86   ASSERT_THAT(ciphertext, IsOk());
87   ASSERT_THAT(cipher_->Decrypt(*ciphertext, kAssociatedData), IsOk());
88   // Modify the ciphertext.
89   for (size_t i = 0; i < ciphertext->size() * 8; i++) {
90     std::string modified_ct = *ciphertext;
91     modified_ct[i / 8] ^= 1 << (i % 8);
92     EXPECT_THAT(cipher_->Decrypt(modified_ct, kAssociatedData).status(),
93                 Not(IsOk()))
94         << i;
95   }
96   // Modify the associated  data.
97   for (size_t i = 0; i < kAssociatedData.size() * 8; i++) {
98     std::string modified_ad = std::string(kAssociatedData);
99     modified_ad[i / 8] ^= 1 << (i % 8);
100     auto decrypted = cipher_->Decrypt(*ciphertext, modified_ad);
101     EXPECT_THAT(decrypted, Not(IsOk())) << i << " pt:" << *decrypted;
102   }
103   // Truncate the ciphertext.
104   for (size_t i = 0; i < ciphertext->size(); i++) {
105     std::string truncated_ct(*ciphertext, 0, i);
106     EXPECT_THAT(cipher_->Decrypt(truncated_ct, kAssociatedData).status(),
107                 Not(IsOk()))
108         << i;
109   }
110 }
111 
TestDecryptWithEmptyAssociatedData(Aead * cipher,absl::string_view ct,absl::string_view message)112 void TestDecryptWithEmptyAssociatedData(Aead* cipher, absl::string_view ct,
113                              absl::string_view message) {
114   {  // associated_data is a null string_view.
115     const absl::string_view associated_data;
116     util::StatusOr<std::string> plaintext =
117         cipher->Decrypt(ct, associated_data);
118     EXPECT_THAT(plaintext, IsOk());
119     EXPECT_EQ(message, *plaintext);
120   }
121   {  // associated_data is a an empty string.
122     util::StatusOr<std::string> plaintext = cipher->Decrypt(ct, "");
123     EXPECT_THAT(plaintext, IsOk());
124     EXPECT_EQ(message, *plaintext);
125   }
126   {  // associated_data is a default constructed string_view.
127     util::StatusOr<std::string> plaintext =
128         cipher->Decrypt(ct, absl::string_view());
129     EXPECT_THAT(plaintext, IsOk());
130     EXPECT_EQ(message, *plaintext);
131   }
132 }
133 
TEST_F(AesGcmBoringSslTest,AssociatedDataEmptyVersusNullStringView)134 TEST_F(AesGcmBoringSslTest, AssociatedDataEmptyVersusNullStringView) {
135   {
136     // associated_data is a null string_view.
137     const absl::string_view associated_data;
138     auto ciphertext = cipher_->Encrypt(kMessage, associated_data);
139     EXPECT_THAT(ciphertext, IsOk());
140     TestDecryptWithEmptyAssociatedData(cipher_.get(), *ciphertext, kMessage);
141   }
142   {  // associated_data is a an empty string.
143     auto ciphertext = cipher_->Encrypt(kMessage, "");
144     EXPECT_THAT(ciphertext, IsOk());
145     TestDecryptWithEmptyAssociatedData(cipher_.get(), *ciphertext, kMessage);
146   }
147   {  // associated_data is a default constructed string_view.
148     auto ciphertext = cipher_->Encrypt(kMessage, absl::string_view());
149     EXPECT_THAT(ciphertext, IsOk());
150     TestDecryptWithEmptyAssociatedData(cipher_.get(), *ciphertext, kMessage);
151   }
152 }
153 
TEST_F(AesGcmBoringSslTest,MessageEmptyVersusNullStringView)154 TEST_F(AesGcmBoringSslTest, MessageEmptyVersusNullStringView) {
155   {  // Message is a null string_view.
156     const absl::string_view message;
157     util::StatusOr<std::string> ciphertext =
158         cipher_->Encrypt(message, kAssociatedData);
159     ASSERT_THAT(ciphertext, IsOk());
160     auto plaintext = cipher_->Decrypt(*ciphertext, kAssociatedData);
161     ASSERT_THAT(plaintext, IsOk());
162     EXPECT_EQ(*plaintext, "");
163   }
164   {  // Message is an empty string.
165     const std::string message = "";
166     util::StatusOr<std::string> ciphertext =
167         cipher_->Encrypt(message, kAssociatedData);
168     ASSERT_THAT(ciphertext, IsOk());
169     auto plaintext = cipher_->Decrypt(*ciphertext, kAssociatedData);
170     ASSERT_THAT(plaintext, IsOk());
171     EXPECT_EQ(*plaintext, "");
172   }
173   {  // Message is a default constructed string_view.
174     util::StatusOr<std::string> ciphertext =
175         cipher_->Encrypt(absl::string_view(), kAssociatedData);
176     ASSERT_THAT(ciphertext, IsOk());
177     auto plaintext = cipher_->Decrypt(*ciphertext, kAssociatedData);
178     ASSERT_THAT(plaintext, IsOk());
179     EXPECT_EQ(*plaintext, "");
180   }
181 }
182 
TEST_F(AesGcmBoringSslTest,BothMessageAndAssociatedDataEmpty)183 TEST_F(AesGcmBoringSslTest, BothMessageAndAssociatedDataEmpty) {
184   {  // Both are null string_view.
185     const absl::string_view message;
186     const absl::string_view associated_data;
187     util::StatusOr<std::string> ciphertext =
188         cipher_->Encrypt(message, associated_data);
189     ASSERT_THAT(ciphertext, IsOk());
190     auto plaintext = cipher_->Decrypt(*ciphertext, associated_data);
191     ASSERT_THAT(plaintext, IsOk());
192     EXPECT_EQ(*plaintext, "");
193   }
194   {  // Both are empty string.
195     const std::string message = "";
196     const std::string associated_data = "";
197     util::StatusOr<std::string> ciphertext =
198         cipher_->Encrypt(message, associated_data);
199     ASSERT_THAT(ciphertext, IsOk());
200     auto plaintext = cipher_->Decrypt(*ciphertext, associated_data);
201     ASSERT_THAT(plaintext, IsOk());
202     EXPECT_EQ(*plaintext, "");
203   }
204   {  // Both are default constructed string_view.
205     util::StatusOr<std::string> ciphertext =
206         cipher_->Encrypt(absl::string_view(), absl::string_view());
207     ASSERT_THAT(ciphertext, IsOk());
208     auto plaintext = cipher_->Decrypt(*ciphertext, absl::string_view());
209     ASSERT_THAT(plaintext, IsOk());
210     EXPECT_EQ(*plaintext, "");
211   }
212 }
213 
TEST_F(AesGcmBoringSslTest,InvalidKeySizes)214 TEST_F(AesGcmBoringSslTest, InvalidKeySizes) {
215   for (int keysize = 0; keysize < 65; keysize++) {
216     util::SecretData key(keysize, 'x');
217     util::StatusOr<std::unique_ptr<crypto::tink::Aead>> cipher =
218         AesGcmBoringSsl::New(key);
219     if (keysize == 16 || keysize == 32) {
220       EXPECT_THAT(cipher, IsOk());
221     } else {
222       EXPECT_THAT(cipher, Not(IsOk()));
223     }
224   }
225 }
226 
TEST(AesGcmBoringSslFipsTest,FipsOnly)227 TEST(AesGcmBoringSslFipsTest, FipsOnly) {
228   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
229     GTEST_SKIP()
230         << "Test should not run in FIPS mode when BoringCrypto is unavailable.";
231   }
232 
233   util::SecretData key_128 =
234       util::SecretDataFromStringView(absl::HexStringToBytes(kKey128));
235   util::SecretData key_256 =
236       util::SecretDataFromStringView(absl::HexStringToBytes(kKey256));
237 
238   EXPECT_THAT(AesGcmBoringSsl::New(key_128), IsOk());
239   EXPECT_THAT(AesGcmBoringSsl::New(key_256), IsOk());
240 }
241 
TEST(AesGcmBoringSslFipsTest,FipsFailWithoutBoringCrypto)242 TEST(AesGcmBoringSslFipsTest, FipsFailWithoutBoringCrypto) {
243   if (!internal::IsFipsModeEnabled() || internal::IsFipsEnabledInSsl()) {
244     GTEST_SKIP()
245         << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
246   }
247 
248   util::SecretData key_128 =
249       util::SecretDataFromStringView(absl::HexStringToBytes(kKey128));
250   util::SecretData key_256 =
251       util::SecretDataFromStringView(absl::HexStringToBytes(kKey256));
252 
253   EXPECT_THAT(AesGcmBoringSsl::New(key_128).status(),
254               StatusIs(absl::StatusCode::kInternal));
255   EXPECT_THAT(AesGcmBoringSsl::New(key_256).status(),
256               StatusIs(absl::StatusCode::kInternal));
257 }
258 
259 class AesGcmBoringSslWycheproofTest
260     : public TestWithParam<internal::WycheproofTestVector> {
SetUp()261   void SetUp() override {
262     if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
263       GTEST_SKIP() << "Test should not run in FIPS mode when BoringCrypto is "
264                       "unavailable.";
265     }
266     internal::WycheproofTestVector test_vector = GetParam();
267     if ((test_vector.key.size() != 16 && test_vector.key.size() != 32) ||
268         test_vector.nonce.size() != 12 || test_vector.tag.size() != 16) {
269       GTEST_SKIP() << "Unsupported parameters: key size "
270                    << test_vector.key.size()
271                    << " nonce size: " << test_vector.nonce.size()
272                    << " tag size: " << test_vector.tag.size();
273     }
274   }
275 };
276 
TEST_P(AesGcmBoringSslWycheproofTest,Decrypt)277 TEST_P(AesGcmBoringSslWycheproofTest, Decrypt) {
278   internal::WycheproofTestVector test_vector = GetParam();
279   util::SecretData key = util::SecretDataFromStringView(test_vector.key);
280   util::StatusOr<std::unique_ptr<Aead>> cipher = AesGcmBoringSsl::New(key);
281   ASSERT_THAT(cipher, IsOk());
282   std::string ciphertext =
283       absl::StrCat(test_vector.nonce, test_vector.ct, test_vector.tag);
284   util::StatusOr<std::string> plaintext =
285       (*cipher)->Decrypt(ciphertext, test_vector.aad);
286   if (plaintext.ok()) {
287     EXPECT_NE(test_vector.expected, "invalid");
288     EXPECT_EQ(*plaintext, test_vector.msg);
289   } else {
290     EXPECT_THAT(test_vector.expected, Not(AllOf(Eq("valid"), Eq("acceptable"))))
291         << "Could not decrypt test with tcId: " << test_vector.id
292         << " iv_size: " << test_vector.nonce.size()
293         << " tag_size: " << test_vector.tag.size()
294         << " key_size: " << key.size() << "; error: " << plaintext.status();
295   }
296 }
297 
298 INSTANTIATE_TEST_SUITE_P(AesGcmBoringSslWycheproofTests,
299                          AesGcmBoringSslWycheproofTest,
300                          ValuesIn(internal::ReadWycheproofTestVectors(
301                              /*file_name=*/"aes_gcm_test.json")));
302 
303 }  // namespace
304 }  // namespace subtle
305 }  // namespace tink
306 }  // namespace crypto
307