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