xref: /aosp_15_r20/external/tink/cc/subtle/encrypt_then_authenticate_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/encrypt_then_authenticate.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "gtest/gtest.h"
25 #include "absl/strings/string_view.h"
26 #include "tink/subtle/aes_ctr_boringssl.h"
27 #include "tink/subtle/common_enums.h"
28 #include "tink/subtle/hmac_boringssl.h"
29 #include "tink/subtle/random.h"
30 #include "tink/util/secret_data.h"
31 #include "tink/util/statusor.h"
32 #include "tink/util/test_util.h"
33 
34 namespace crypto {
35 namespace tink {
36 namespace subtle {
37 namespace {
38 
39 // Copied from
40 // https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05.
41 // We use CTR but the RFC uses CBC mode, so it's not possible to compare
42 // plaintexts. However, the tests are still valueable to ensure that we correcly
43 // compute HMAC over ciphertext and associated_data.
44 struct TestVector {
45   absl::string_view mac_key;
46   absl::string_view enc_key;
47   absl::string_view ciphertext;
48   absl::string_view associated_data;
49   HashType hash_type;
50   int iv_size;
51   int tag_size;
52 };
53 
54 constexpr TestVector test_vectors[] = {
55     {"000102030405060708090a0b0c0d0e0f", "101112131415161718191a1b1c1d1e1f",
56      "1af38c2dc2b96ffdd86694092341bc04"
57      "c80edfa32ddf39d5ef00c0b468834279"
58      "a2e46a1b8049f792f76bfe54b903a9c9"
59      "a94ac9b47ad2655c5f10f9aef71427e2"
60      "fc6f9b3f399a221489f16362c7032336"
61      "09d45ac69864e3321cf82935ac4096c8"
62      "6e133314c54019e8ca7980dfa4b9cf1b"
63      "384c486f3a54c51078158ee5d79de59f"
64      "bd34d848b3d69550a67646344427ade5"
65      "4b8851ffb598f7f80074b9473c82e2db"
66      "652c3fa36b0a7c5b3219fab3a30bc1c4",
67      "546865207365636f6e64207072696e63"
68      "69706c65206f66204175677573746520"
69      "4b6572636b686f666673",
70      HashType::SHA256, 16, 16},
71     {"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
72      "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
73      "1af38c2dc2b96ffdd86694092341bc04"
74      "4affaaadb78c31c5da4b1b590d10ffbd"
75      "3dd8d5d302423526912da037ecbcc7bd"
76      "822c301dd67c373bccb584ad3e9279c2"
77      "e6d12a1374b77f077553df829410446b"
78      "36ebd97066296ae6427ea75c2e0846a1"
79      "1a09ccf5370dc80bfecbad28c73f09b3"
80      "a3b75e662a2594410ae496b2e2e6609e"
81      "31e6e02cc837f053d21f37ff4f51950b"
82      "be2638d09dd7a4930930806d0703b1f6"
83      "4dd3b4c088a7f45c216839645b2012bf"
84      "2e6269a8c56a816dbc1b267761955bc5",
85      "546865207365636f6e64207072696e63"
86      "69706c65206f66204175677573746520"
87      "4b6572636b686f666673",
88      HashType::SHA512, 16, 32},
89 };
90 
createAead2(util::SecretData encryption_key,int iv_size,util::SecretData mac_key,uint8_t tag_size,HashType hash_type)91 util::StatusOr<std::unique_ptr<Aead>> createAead2(
92     util::SecretData encryption_key, int iv_size, util::SecretData mac_key,
93     uint8_t tag_size, HashType hash_type) {
94   auto ind_cipher_res =
95       AesCtrBoringSsl::New(std::move(encryption_key), iv_size);
96   if (!ind_cipher_res.ok()) {
97     return ind_cipher_res.status();
98   }
99 
100   auto mac_res = HmacBoringSsl::New(hash_type, tag_size, std::move(mac_key));
101   if (!mac_res.ok()) {
102     return mac_res.status();
103   }
104   auto cipher_res = EncryptThenAuthenticate::New(
105       std::move(ind_cipher_res.value()), std::move(mac_res.value()), tag_size);
106   if (!cipher_res.ok()) {
107     return cipher_res.status();
108   }
109   return std::move(cipher_res.value());
110 }
111 
createAead(int encryption_key_size,int iv_size,int mac_key_size,int tag_size,HashType hash_type)112 util::StatusOr<std::unique_ptr<Aead>> createAead(int encryption_key_size,
113                                                  int iv_size, int mac_key_size,
114                                                  int tag_size,
115                                                  HashType hash_type) {
116   util::SecretData encryption_key =
117       Random::GetRandomKeyBytes(encryption_key_size);
118   util::SecretData mac_key = Random::GetRandomKeyBytes(mac_key_size);
119   return createAead2(std::move(encryption_key), iv_size, std::move(mac_key),
120                      tag_size, hash_type);
121 }
122 
TEST(AesGcmBoringSslTest,testRfcVectors)123 TEST(AesGcmBoringSslTest, testRfcVectors) {
124   for (const TestVector& test : test_vectors) {
125     util::SecretData mac_key =
126         util::SecretDataFromStringView(test::HexDecodeOrDie(test.mac_key));
127     util::SecretData enc_key =
128         util::SecretDataFromStringView(test::HexDecodeOrDie(test.enc_key));
129     std::string ct = test::HexDecodeOrDie(test.ciphertext);
130     std::string associated_data = test::HexDecodeOrDie(test.associated_data);
131     auto res = createAead2(std::move(enc_key), test.iv_size, std::move(mac_key),
132                            test.tag_size, test.hash_type);
133     EXPECT_TRUE(res.ok()) << res.status();
134     auto cipher = std::move(res.value());
135     auto pt = cipher->Decrypt(ct, associated_data);
136     EXPECT_TRUE(pt.ok()) << pt.status();
137   }
138 }
139 
TEST(EncryptThenAuthenticateTest,testEncryptDecrypt)140 TEST(EncryptThenAuthenticateTest, testEncryptDecrypt) {
141   int encryption_key_size = 16;
142   int iv_size = 12;
143   int mac_key_size = 16;
144   int tag_size = 16;
145   auto res = createAead(encryption_key_size, iv_size, mac_key_size, tag_size,
146                         HashType::SHA1);
147   EXPECT_TRUE(res.ok()) << res.status();
148   auto cipher = std::move(res.value());
149 
150   std::string message = "Some data to encrypt.";
151   std::string associated_data = "Some associated data.";
152   auto ct = cipher->Encrypt(message, associated_data);
153   EXPECT_TRUE(ct.ok()) << ct.status();
154   EXPECT_EQ(ct.value().size(), message.size() + iv_size + tag_size);
155   auto pt = cipher->Decrypt(ct.value(), associated_data);
156   EXPECT_TRUE(pt.ok()) << pt.status();
157   EXPECT_EQ(pt.value(), message);
158 }
159 
TEST(EncryptThenAuthenticateTest,testEncryptDecrypt_randomMessage)160 TEST(EncryptThenAuthenticateTest, testEncryptDecrypt_randomMessage) {
161   int encryption_key_size = 16;
162   int iv_size = 12;
163   int mac_key_size = 16;
164   int tag_size = 16;
165   auto res = createAead(encryption_key_size, iv_size, mac_key_size, tag_size,
166                         HashType::SHA1);
167   EXPECT_TRUE(res.ok()) << res.status();
168   auto cipher = std::move(res.value());
169 
170   for (int i = 0; i < 256; i++) {
171     std::string message = Random::GetRandomBytes(i);
172     std::string associated_data = Random::GetRandomBytes(i);
173     auto ct = cipher->Encrypt(message, associated_data);
174     EXPECT_TRUE(ct.ok()) << ct.status();
175     EXPECT_EQ(ct.value().size(), message.size() + iv_size + tag_size);
176     auto pt = cipher->Decrypt(ct.value(), associated_data);
177     EXPECT_TRUE(pt.ok()) << pt.status();
178     EXPECT_EQ(pt.value(), message);
179   }
180 }
181 
TEST(AesCtrBoringSslTest,testMultipleEncrypt)182 TEST(AesCtrBoringSslTest, testMultipleEncrypt) {
183   int encryption_key_size = 16;
184   int iv_size = 12;
185   int mac_key_size = 16;
186   int tag_size = 16;
187   auto res = createAead(encryption_key_size, iv_size, mac_key_size, tag_size,
188                         HashType::SHA1);
189   EXPECT_TRUE(res.ok()) << res.status();
190   auto cipher = std::move(res.value());
191 
192   std::string message = Random::GetRandomBytes(20);
193   std::string associated_data = Random::GetRandomBytes(20);
194   auto ct1 = cipher->Encrypt(message, associated_data);
195   auto ct2 = cipher->Encrypt(message, associated_data);
196   EXPECT_NE(ct1.value(), ct2.value());
197 }
198 
TEST(EncryptThenAuthenticateTest,testEncryptDecrypt_invalidTagSize)199 TEST(EncryptThenAuthenticateTest, testEncryptDecrypt_invalidTagSize) {
200   int encryption_key_size = 16;
201   int iv_size = 12;
202   int mac_key_size = 16;
203   int tag_size = 9;
204   auto res = createAead(encryption_key_size, iv_size, mac_key_size, tag_size,
205                         HashType::SHA1);
206   EXPECT_FALSE(res.ok()) << res.status();
207 }
208 
TEST(EncryptThenAuthenticateTest,testDecrypt_modifiedCiphertext)209 TEST(EncryptThenAuthenticateTest, testDecrypt_modifiedCiphertext) {
210   int encryption_key_size = 16;
211   int iv_size = 12;
212   int mac_key_size = 16;
213   int tag_size = 16;
214   auto res = createAead(encryption_key_size, iv_size, mac_key_size, tag_size,
215                         HashType::SHA1);
216   EXPECT_TRUE(res.ok()) << res.status();
217   auto cipher = std::move(res.value());
218 
219   std::string message = "Some data to encrypt.";
220   std::string associated_data = "Some data to authenticate.";
221   std::string ct = cipher->Encrypt(message, associated_data).value();
222   EXPECT_TRUE(cipher->Decrypt(ct, associated_data).ok());
223   // Modify the ciphertext
224   for (size_t i = 0; i < ct.size() * 8; i++) {
225     std::string modified_ct = ct;
226     modified_ct[i / 8] ^= 1 << (i % 8);
227     EXPECT_FALSE(cipher->Decrypt(modified_ct, associated_data).ok()) << i;
228   }
229 
230   // Modify the associated data
231   for (size_t i = 0; i < associated_data.size() * 8; i++) {
232     std::string modified_associated_data = associated_data;
233     modified_associated_data[i / 8] ^= 1 << (i % 8);
234     auto decrypted = cipher->Decrypt(ct, modified_associated_data);
235     EXPECT_FALSE(decrypted.ok()) << i << " pt:" << decrypted.value();
236   }
237 
238   // Truncate the ciphertext
239   for (size_t i = 0; i < ct.size(); i++) {
240     std::string truncated_ct(ct, 0, i);
241     EXPECT_FALSE(cipher->Decrypt(truncated_ct, associated_data).ok()) << i;
242   }
243 }
244 
TEST(EncryptThenAuthenticateTest,testParamsEmptyVersusNullStringView)245 TEST(EncryptThenAuthenticateTest, testParamsEmptyVersusNullStringView) {
246   int encryption_key_size = 16;
247   int iv_size = 12;
248   int mac_key_size = 16;
249   int tag_size = 16;
250   auto cipher = std::move(createAead(encryption_key_size, iv_size, mac_key_size,
251                                      tag_size, HashType::SHA1)
252                               .value());
253 
254   {  // associated_data null string_view.
255     const std::string message = "Some data to encrypt.";
256     const absl::string_view associated_data;
257     const std::string ct = cipher->Encrypt(message, "").value();
258     EXPECT_TRUE(cipher->Decrypt(ct, associated_data).ok());
259   }
260   {  // Both message and associated_data null string_view.
261     const absl::string_view message;
262     const absl::string_view associated_data;
263     const std::string ct = cipher->Encrypt(message, "").value();
264     EXPECT_TRUE(cipher->Decrypt(ct, associated_data).ok());
265   }
266 }
267 
268 // EncryptThenAuthenticate computes the MAC over associated_data || ciphertext
269 // || associated_data_size_in_bits, where associated_data_size_in_bits =
270 // associated_data.size() * 8 [1]. associated_data.size() returns a size_t which
271 // is usually unsigned long or unsigned long long. On 32-bit machines (and maybe
272 // others), long is 32-bit int. If associated_data.size() returns a number equal
273 // to or larger than 2^29, an overflow will occur when multiplying with 8 to get
274 // the size in bits. This leads to an authentication bypass vulnerability. This
275 // test ensures that the overflow issue and the auth bypass vulnerability are
276 // fixed.
TEST(EncryptThenAuthenticateTest,testAuthBypassShouldNotWork)277 TEST(EncryptThenAuthenticateTest, testAuthBypassShouldNotWork) {
278   int encryption_key_size = 16;
279   int iv_size = 12;
280   int mac_key_size = 16;
281   int tag_size = 16;
282   auto cipher = std::move(createAead(encryption_key_size, iv_size, mac_key_size,
283                                      tag_size, HashType::SHA1)
284                               .value());
285 
286   // Encrypt a message...
287   const std::string message = "Some data to encrypt.";
288   // ...with a long associated_data whose size in bits converted to an unsigned
289   // 32-bit integer is 0.
290   std::string associated_data;
291   constexpr size_t kAssociatedDataSize = 1 << 29;
292   constexpr size_t kCiphertextSpace = 1000;
293   associated_data.reserve(kAssociatedDataSize + kCiphertextSpace);
294   associated_data.resize(kAssociatedDataSize, 'a');
295   auto encrypted = cipher->Encrypt(message, associated_data);
296   EXPECT_TRUE(encrypted.ok()) << encrypted.status();
297   auto ct = encrypted.value();
298   auto decrypted = cipher->Decrypt(ct, associated_data);
299   EXPECT_TRUE(decrypted.ok()) << decrypted.status();
300 
301   // Test that the 2^29-byte associated_data is NOT considered equal to an empty
302   // associated_data. That is, test that a valid tag for (ciphertext,
303   // associated_data) is INVALID for (associated_data + ciphertext, "").
304   ct = std::move(associated_data) + ct;
305   decrypted = cipher->Decrypt(ct, "");
306   EXPECT_FALSE(decrypted.ok());
307 }
308 
309 }  // namespace
310 }  // namespace subtle
311 }  // namespace tink
312 }  // namespace crypto
313