xref: /aosp_15_r20/external/tink/cc/aead/internal/zero_copy_aes_gcm_boringssl_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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 
17 #include "tink/aead/internal/zero_copy_aes_gcm_boringssl.h"
18 
19 #include <algorithm>
20 #include <cstring>
21 #include <iterator>
22 #include <memory>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/escaping.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/types/span.h"
33 #include "tink/aead/internal/wycheproof_aead.h"
34 #include "tink/aead/internal/zero_copy_aead.h"
35 #include "tink/subtle/subtle_util.h"
36 #include "tink/util/statusor.h"
37 #include "tink/util/test_matchers.h"
38 
39 namespace crypto {
40 namespace tink {
41 namespace internal {
42 namespace {
43 
44 using ::crypto::tink::test::IsOk;
45 using ::crypto::tink::test::StatusIs;
46 using ::testing::AllOf;
47 using ::testing::Eq;
48 using ::testing::Not;
49 using ::testing::TestWithParam;
50 using ::testing::ValuesIn;
51 
52 constexpr absl::string_view kKey128Hex = "000102030405060708090a0b0c0d0e0f";
53 constexpr absl::string_view kMessage = "Some data to encrypt.";
54 constexpr absl::string_view kAssociatedData = "Some data to authenticate.";
55 
56 constexpr int kIvSizeInBytes = 12;
57 constexpr int kTagSizeInBytes = 16;
58 
59 // The MaxSizes test verifies these constants.
60 constexpr int64_t kMaxEncryptionSize =
61     kMessage.size() + kIvSizeInBytes + kTagSizeInBytes;
62 // kMaxEncryptionSize - kIvSize - kTagSize.
63 constexpr int64_t kMaxDecryptionSize = kMessage.size();
64 
65 // Encoded ciphertext of kMessage with kAssociatedData and kKey128Hex.
66 constexpr absl::string_view kEncodedCiphertext =
67     "22889553081aa27f0f62ed2f32b068331cb3d8103e121c8b0c898cf70b613e334b7e913323"
68     "128429226950dd2f4d42a6fc";
69 
70 class ZeroCopyAesGcmBoringSslTest : public testing::Test {
71  protected:
SetUp()72   void SetUp() override {
73     util::SecretData key =
74         util::SecretDataFromStringView(absl::HexStringToBytes(kKey128Hex));
75     util::StatusOr<std::unique_ptr<ZeroCopyAead>> cipher =
76         ZeroCopyAesGcmBoringSsl::New(key);
77     ASSERT_THAT(cipher, IsOk());
78     cipher_ = std::move(*cipher);
79   }
80 
81   std::unique_ptr<ZeroCopyAead> cipher_;
82 };
83 
TEST_F(ZeroCopyAesGcmBoringSslTest,MaxDecryptionSizeOfMaxEncryptionSizeOfMessageIsMessageSize)84 TEST_F(ZeroCopyAesGcmBoringSslTest,
85        MaxDecryptionSizeOfMaxEncryptionSizeOfMessageIsMessageSize) {
86   // Check i == MaxDecryptionSize(MaxEncryptionSize(i)).
87   EXPECT_EQ(kMessage.size(), cipher_->MaxDecryptionSize(
88                                  cipher_->MaxEncryptionSize(kMessage.size())));
89 }
90 
TEST_F(ZeroCopyAesGcmBoringSslTest,EncryptDecrypt)91 TEST_F(ZeroCopyAesGcmBoringSslTest, EncryptDecrypt) {
92   std::string ciphertext;
93   subtle::ResizeStringUninitialized(
94       &ciphertext, cipher_->MaxEncryptionSize(kMessage.size()));
95   util::StatusOr<int64_t> ciphertext_size =
96       cipher_->Encrypt(kMessage, kAssociatedData, absl::MakeSpan(ciphertext));
97   ASSERT_THAT(ciphertext_size, IsOk());
98   EXPECT_EQ(*ciphertext_size,
99             kIvSizeInBytes + kMessage.size() + kTagSizeInBytes);
100   std::string plaintext;
101   subtle::ResizeStringUninitialized(
102       &plaintext, cipher_->MaxDecryptionSize(ciphertext.size()));
103   util::StatusOr<int64_t> plaintext_size =
104       cipher_->Decrypt(ciphertext, kAssociatedData, absl::MakeSpan(plaintext));
105 
106   ASSERT_THAT(plaintext_size, IsOk());
107   EXPECT_EQ(plaintext, kMessage);
108 }
109 
TEST_F(ZeroCopyAesGcmBoringSslTest,DecryptEncodedCiphertext)110 TEST_F(ZeroCopyAesGcmBoringSslTest, DecryptEncodedCiphertext) {
111   std::string plaintext;
112   subtle::ResizeStringUninitialized(&plaintext, kMaxDecryptionSize);
113   util::StatusOr<int64_t> plaintext_size =
114       cipher_->Decrypt(absl::HexStringToBytes(kEncodedCiphertext),
115                        kAssociatedData, absl::MakeSpan(plaintext));
116   ASSERT_THAT(plaintext_size, IsOk());
117   EXPECT_EQ(plaintext.substr(0, *plaintext_size), kMessage);
118 }
119 
TEST_F(ZeroCopyAesGcmBoringSslTest,EncryptBufferTooSmall)120 TEST_F(ZeroCopyAesGcmBoringSslTest, EncryptBufferTooSmall) {
121   const int64_t kMaxEncryptionSize =
122       kMessage.size() + kIvSizeInBytes + kTagSizeInBytes;
123   std::string ciphertext;
124   subtle::ResizeStringUninitialized(&ciphertext, kMaxEncryptionSize - 1);
125   EXPECT_THAT(
126       cipher_->Encrypt(kMessage, kAssociatedData, absl::MakeSpan(ciphertext))
127           .status(),
128       StatusIs(absl::StatusCode::kInvalidArgument));
129 }
130 
TEST_F(ZeroCopyAesGcmBoringSslTest,DecryptBufferTooSmall)131 TEST_F(ZeroCopyAesGcmBoringSslTest, DecryptBufferTooSmall) {
132   const int64_t kMaxDecryptionSize = kMessage.size();
133   std::string plaintext;
134   subtle::ResizeStringUninitialized(&plaintext, kMaxDecryptionSize - 1);
135   EXPECT_THAT(cipher_
136                   ->Decrypt(absl::HexStringToBytes(kEncodedCiphertext),
137                             kAssociatedData, absl::MakeSpan(plaintext))
138                   .status(),
139               StatusIs(absl::StatusCode::kInvalidArgument));
140 }
141 
TEST_F(ZeroCopyAesGcmBoringSslTest,EncryptOverlappingPlaintextCiphertext)142 TEST_F(ZeroCopyAesGcmBoringSslTest, EncryptOverlappingPlaintextCiphertext) {
143   std::string buffer(1024, '\0');
144   // Copy the kMessage at the beginning of the buffer.
145   std::copy(kMessage.begin(), kMessage.end(), std::back_inserter(buffer));
146   auto plaintext = absl::string_view(buffer).substr(0, kMessage.size());
147   // The output buffer overlaps with a portion of the plaintext, in particular
148   // the last kIvSizeInBytes bytes.
149   auto cipher_buff =
150       absl::MakeSpan(buffer).subspan(kMessage.size() - kIvSizeInBytes);
151   EXPECT_THAT(
152       cipher_->Encrypt(plaintext, kAssociatedData, cipher_buff).status(),
153       StatusIs(absl::StatusCode::kFailedPrecondition));
154 }
155 
TEST_F(ZeroCopyAesGcmBoringSslTest,DecryptOverlappingPlaintextCiphertext)156 TEST_F(ZeroCopyAesGcmBoringSslTest, DecryptOverlappingPlaintextCiphertext) {
157   std::string buffer(1024, '\0');
158   // Plaintext's buffer starts at the beginning of the buffer.
159   auto out_buffer = absl::MakeSpan(buffer).subspan(0, kMessage.size());
160   std::string ciphertext_data = absl::HexStringToBytes(kEncodedCiphertext);
161   // Copy the ciphertext into buffer such that the IV part will overlap with the
162   // end of the plaintext output buffer.
163   int ciphertext_start = kMessage.size() - kIvSizeInBytes;
164   memcpy(&buffer[0] + ciphertext_start, ciphertext_data.data(),
165          ciphertext_data.size());
166   auto ciphertext = absl::string_view(buffer).substr(ciphertext_start,
167                                                      ciphertext_data.size());
168   EXPECT_THAT(
169       cipher_->Decrypt(ciphertext, kAssociatedData, out_buffer).status(),
170       StatusIs(absl::StatusCode::kFailedPrecondition));
171 }
172 
173 class ZeroCopyAesGcmBoringSslWycheproofTest
174     : public TestWithParam<WycheproofTestVector> {
SetUp()175   void SetUp() override {
176     WycheproofTestVector test_vector = GetParam();
177     if ((test_vector.key.size() != 16 && test_vector.key.size() != 32) ||
178         test_vector.nonce.size() != 12 || test_vector.tag.size() != 16) {
179       GTEST_SKIP() << "Unsupported parameters: key size "
180                    << test_vector.key.size()
181                    << " nonce size: " << test_vector.nonce.size()
182                    << " tag size: " << test_vector.tag.size();
183     }
184   }
185 };
186 
TEST_P(ZeroCopyAesGcmBoringSslWycheproofTest,Decrypt)187 TEST_P(ZeroCopyAesGcmBoringSslWycheproofTest, Decrypt) {
188   WycheproofTestVector test_vector = GetParam();
189   util::SecretData key = util::SecretDataFromStringView(test_vector.key);
190   util::StatusOr<std::unique_ptr<ZeroCopyAead>> cipher =
191       ZeroCopyAesGcmBoringSsl::New(key);
192   ASSERT_THAT(cipher, IsOk());
193   std::string ciphertext =
194       absl::StrCat(test_vector.nonce, test_vector.ct, test_vector.tag);
195   std::string plaintext;
196   subtle::ResizeStringUninitialized(
197       &plaintext, (*cipher)->MaxDecryptionSize(ciphertext.size()));
198   util::StatusOr<int64_t> written_bytes = (*cipher)->Decrypt(
199       ciphertext, test_vector.aad, absl::MakeSpan(plaintext));
200   if (written_bytes.ok()) {
201     EXPECT_NE(test_vector.expected, "invalid");
202     EXPECT_EQ(plaintext, test_vector.msg);
203   } else {
204     EXPECT_THAT(test_vector.expected, Not(AllOf(Eq("valid"), Eq("acceptable"))))
205         << "Could not decrypt test with tcId: " << test_vector.id
206         << " iv_size: " << test_vector.nonce.size()
207         << " tag_size: " << test_vector.tag.size()
208         << " key_size: " << key.size() << "; error: " << written_bytes.status();
209   }
210 }
211 
212 INSTANTIATE_TEST_SUITE_P(ZeroCopyAesGcmBoringSslWycheproofTests,
213                          ZeroCopyAesGcmBoringSslWycheproofTest,
214                          ValuesIn(ReadWycheproofTestVectors(
215                              /*file_name=*/"aes_gcm_test.json")));
216 
217 }  // namespace
218 }  // namespace internal
219 }  // namespace tink
220 }  // namespace crypto
221