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