xref: /aosp_15_r20/external/tink/cc/subtle/streaming_aead_decrypting_stream_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2019 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/streaming_aead_decrypting_stream.h"
18 
19 #include <algorithm>
20 #include <memory>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "gtest/gtest.h"
27 #include "absl/memory/memory.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/string_view.h"
30 #include "tink/input_stream.h"
31 #include "tink/subtle/random.h"
32 #include "tink/subtle/stream_segment_decrypter.h"
33 #include "tink/subtle/test_util.h"
34 #include "tink/util/istream_input_stream.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37 
38 using crypto::tink::InputStream;
39 using crypto::tink::subtle::test::DummyStreamSegmentDecrypter;
40 using crypto::tink::subtle::test::DummyStreamSegmentEncrypter;
41 using crypto::tink::util::IstreamInputStream;
42 
43 namespace crypto {
44 namespace tink {
45 namespace subtle {
46 namespace {
47 
48 // References to objects used for test validation.
49 // The objects pointed to are not owned by this structure.
50 struct ValidationRefs {
51   DummyStreamSegmentDecrypter* seg_dec;  // segment decrypter
52 };
53 
54 // A helper for creating StreamingAeadDecryptingStream together
55 // with references to internal objects, used for test validation.
GetDecryptingStream(int pt_segment_size,int header_size,int ct_offset,absl::string_view ciphertext,ValidationRefs * refs)56 std::unique_ptr<InputStream> GetDecryptingStream(
57     int pt_segment_size, int header_size, int ct_offset,
58     absl::string_view ciphertext, ValidationRefs* refs) {
59   // Prepare ciphertext source stream.
60   auto ct_stream =
61       absl::make_unique<std::stringstream>(std::string(ciphertext));
62   std::unique_ptr<InputStream> ct_source(
63       absl::make_unique<IstreamInputStream>(std::move(ct_stream)));
64   auto seg_dec = absl::make_unique<DummyStreamSegmentDecrypter>(
65           pt_segment_size, header_size, ct_offset);
66   // A reference to the segment decrypter, for later validation.
67   refs->seg_dec = seg_dec.get();
68   auto dec_stream = std::move(StreamingAeadDecryptingStream::New(
69                                   std::move(seg_dec), std::move(ct_source))
70                                   .value());
71   EXPECT_EQ(0, dec_stream->Position());
72   return dec_stream;
73 }
74 
75 
76 class StreamingAeadDecryptingStreamTest : public ::testing::Test {
77 };
78 
TEST_F(StreamingAeadDecryptingStreamTest,WritingStreams)79 TEST_F(StreamingAeadDecryptingStreamTest, WritingStreams) {
80   std::vector<int> pt_sizes = {0, 10, 100, 1000, 10000, 100000, 1000000};
81   std::vector<int> pt_segment_sizes = {64, 100, 128, 1000, 1024};
82   std::vector<int> header_sizes = {5, 10, 32};
83   std::vector<int> ct_offsets = {0, 1, 5, 15};
84   for (auto pt_size : pt_sizes) {
85     for (auto pt_segment_size : pt_segment_sizes) {
86       for (auto header_size : header_sizes) {
87         for (auto ct_offset : ct_offsets) {
88           SCOPED_TRACE(absl::StrCat("pt_size = ", pt_size,
89                                     ", pt_segment_size = ", pt_segment_size,
90                                     ", header_size = ", header_size,
91                                     ", ct_offset = ", ct_offset));
92           // Get a decrypting stream.
93           std::string pt = Random::GetRandomBytes(pt_size);
94           DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
95               ct_offset);
96           std::string ct = seg_enc.GenerateCiphertext(pt);
97 
98           ValidationRefs refs;
99           auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
100               ct_offset, ct, &refs);
101 
102           // First buffer returned by Next();
103           const void* buffer;
104           auto next_result = dec_stream->Next(&buffer);
105           EXPECT_TRUE(next_result.ok()) << next_result.status();
106           int buffer_size = next_result.value();
107           int exp_buffer_size = pt_segment_size - (header_size + ct_offset);
108           if (exp_buffer_size > pt_size) exp_buffer_size = pt_size;
109           EXPECT_EQ(exp_buffer_size, buffer_size);
110           EXPECT_EQ(buffer_size, dec_stream->Position());
111 
112           // Backup the entire first buffer.
113           dec_stream->BackUp(buffer_size);
114           EXPECT_EQ(0, dec_stream->Position());
115 
116           // Read the entire plaintext to the stream.
117           std::string decrypted;
118           auto status = test::ReadFromStream(dec_stream.get(), &decrypted);
119           EXPECT_TRUE(status.ok()) << status;
120           EXPECT_EQ(dec_stream->Position(), pt.size());
121           EXPECT_EQ(pt, decrypted);
122         }
123       }
124     }
125   }
126 }
127 
TEST_F(StreamingAeadDecryptingStreamTest,EmptyCiphertext)128 TEST_F(StreamingAeadDecryptingStreamTest, EmptyCiphertext) {
129   int pt_segment_size = 512;
130   int header_size = 64;
131 
132   // Get a decrypting stream.
133   ValidationRefs refs;
134   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
135       /* ct_offset = */ 0, /* ciphertext = */ "", &refs);
136 
137   // First buffer returned by Next();
138   const void* buffer;
139   auto next_result = dec_stream->Next(&buffer);
140   EXPECT_FALSE(next_result.ok());
141   EXPECT_EQ(next_result.status().code(), absl::StatusCode::kInvalidArgument);
142   EXPECT_PRED_FORMAT2(testing::IsSubstring, "Could not read stream header",
143                       std::string(next_result.status().message()));
144 }
145 
TEST_F(StreamingAeadDecryptingStreamTest,InvalidStreamHeader)146 TEST_F(StreamingAeadDecryptingStreamTest, InvalidStreamHeader) {
147   int pt_segment_size = 512;
148   int header_size = 64;
149 
150   // Get a decrypting stream.
151   ValidationRefs refs;
152   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
153                                         /* ct_offset = */ 0,
154                                         std::string(header_size, 'a'), &refs);
155 
156   // First buffer returned by Next();
157   const void* buffer;
158   auto next_result = dec_stream->Next(&buffer);
159   EXPECT_FALSE(next_result.ok());
160   EXPECT_EQ(next_result.status().code(), absl::StatusCode::kInvalidArgument);
161   EXPECT_PRED_FORMAT2(testing::IsSubstring, "Invalid stream header",
162                       std::string(next_result.status().message()));
163 }
164 
TEST_F(StreamingAeadDecryptingStreamTest,TruncatedLastSegment)165 TEST_F(StreamingAeadDecryptingStreamTest, TruncatedLastSegment) {
166   int pt_segment_size = 120;
167   int pt_size = 500;
168   int header_size = 64;
169 
170   // Get a decrypting stream.
171   std::string pt = Random::GetRandomBytes(pt_size);
172   DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
173       /* ct_offset = */ 0);
174   std::string ct = seg_enc.GenerateCiphertext(pt);
175 
176   ValidationRefs refs;
177   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
178       /* ct_offset = */ 0, ct.substr(0, ct.size()-2), &refs);
179 
180   // First buffer returned by Next();
181   std::string decrypted;
182   auto status = test::ReadFromStream(dec_stream.get(), &decrypted);
183   EXPECT_FALSE(status.ok());
184   EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
185   EXPECT_PRED_FORMAT2(testing::IsSubstring, "unexpected last-segment marker",
186                       std::string(status.message()));
187 }
188 
189 
TEST_F(StreamingAeadDecryptingStreamTest,OneSegmentPlaintext)190 TEST_F(StreamingAeadDecryptingStreamTest, OneSegmentPlaintext) {
191   int pt_segment_size = 512;
192   int header_size = 64;
193 
194   // Get a decrypting stream.
195   std::string pt = Random::GetRandomBytes(pt_segment_size - header_size);
196   DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
197       /* ct_offset = */ 0);
198   std::string ct = seg_enc.GenerateCiphertext(pt);
199   EXPECT_EQ(seg_enc.get_ciphertext_segment_size(), ct.size());
200 
201   ValidationRefs refs;
202   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
203       /* ct_offset = */ 0, ct, &refs);
204 
205   // Get the first segment.
206   const void* buffer;
207   auto next_result = dec_stream->Next(&buffer);
208   int buffer_size = pt_segment_size - header_size;
209   EXPECT_TRUE(next_result.ok()) << next_result.status();
210   EXPECT_EQ(buffer_size, next_result.value());
211   EXPECT_EQ(buffer_size, dec_stream->Position());
212   EXPECT_EQ(pt,
213             std::string(reinterpret_cast<const char*>(buffer), buffer_size));
214 
215   // Try getting another segment.
216   next_result = dec_stream->Next(&buffer);
217   EXPECT_FALSE(next_result.ok());
218   EXPECT_EQ(absl::StatusCode::kOutOfRange, next_result.status().code());
219 }
220 
221 
TEST_F(StreamingAeadDecryptingStreamTest,OneSegmentAndOneBytePlaintext)222 TEST_F(StreamingAeadDecryptingStreamTest, OneSegmentAndOneBytePlaintext) {
223   int pt_segment_size = 512;
224   int header_size = 64;
225 
226   // Get a decrypting stream.
227   std::string pt = Random::GetRandomBytes(pt_segment_size - header_size + 1);
228   DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
229       /* ct_offset = */ 0);
230   std::string ct = seg_enc.GenerateCiphertext(pt);
231   EXPECT_EQ(seg_enc.get_ciphertext_segment_size() +
232             DummyStreamSegmentEncrypter::kSegmentTagSize + 1,
233             ct.size());
234 
235   ValidationRefs refs;
236   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
237       /* ct_offset = */ 0, ct, &refs);
238 
239   // Get the first segment.
240   const void* buffer;
241   auto next_result = dec_stream->Next(&buffer);
242   int buffer_size = pt_segment_size - header_size;
243   EXPECT_TRUE(next_result.ok()) << next_result.status();
244   EXPECT_EQ(buffer_size, next_result.value());
245   EXPECT_EQ(buffer_size, dec_stream->Position());
246   EXPECT_EQ(pt.substr(0, buffer_size),
247             std::string(reinterpret_cast<const char*>(buffer), buffer_size));
248 
249   // Get the second segment.
250   next_result = dec_stream->Next(&buffer);
251   EXPECT_TRUE(next_result.ok()) << next_result.status();
252   EXPECT_EQ(1, next_result.value());
253   EXPECT_EQ(pt.size(), dec_stream->Position());
254   EXPECT_EQ(pt.at(pt.size()-1), *(reinterpret_cast<const char*>(buffer)));
255 
256   // Try getting another segment.
257   next_result = dec_stream->Next(&buffer);
258   EXPECT_FALSE(next_result.ok());
259   EXPECT_EQ(absl::StatusCode::kOutOfRange, next_result.status().code());
260 }
261 
TEST_F(StreamingAeadDecryptingStreamTest,NextAfterBackUp)262 TEST_F(StreamingAeadDecryptingStreamTest, NextAfterBackUp) {
263   int pt_segment_size = 97;
264   int pt_size = 334;
265   int header_size = 30;
266 
267   // Get a decrypting stream.
268   std::string pt = Random::GetRandomBytes(pt_size);
269   DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
270       /* ct_offset = */ 0);
271   std::string ct = seg_enc.GenerateCiphertext(pt);
272   ValidationRefs refs;
273   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
274       /* ct_offset = */ 0, ct, &refs);
275 
276   // Get the first segment.
277   const void* buffer;
278   auto next_result = dec_stream->Next(&buffer);
279   int buffer_size = pt_segment_size - header_size;
280   EXPECT_TRUE(next_result.ok()) << next_result.status();
281   EXPECT_EQ(buffer_size, next_result.value());
282   EXPECT_EQ(buffer_size, dec_stream->Position());
283   EXPECT_EQ(pt.substr(0, buffer_size),
284             std::string(reinterpret_cast<const char*>(buffer), buffer_size));
285   std::string decrypted_first_segment(reinterpret_cast<const char*>(buffer),
286                                       buffer_size);
287 
288   // Backup part of the first segment, and call Next again.
289   int backup_size = buffer_size / 2;
290   dec_stream->BackUp(backup_size);
291   EXPECT_EQ(buffer_size - backup_size, dec_stream->Position());
292   next_result = dec_stream->Next(&buffer);
293   EXPECT_TRUE(next_result.ok()) << next_result.status();
294   EXPECT_EQ(backup_size, next_result.value());
295   EXPECT_EQ(buffer_size, dec_stream->Position());
296   EXPECT_EQ(pt.substr(buffer_size - backup_size, backup_size),
297             std::string(reinterpret_cast<const char*>(buffer), backup_size));
298 
299   // Backup a smaller part of the first segment, and call Next again.
300   int backup2_size = buffer_size / 4;
301   dec_stream->BackUp(backup2_size);
302   EXPECT_EQ(buffer_size - backup2_size, dec_stream->Position());
303   next_result = dec_stream->Next(&buffer);
304   EXPECT_TRUE(next_result.ok()) << next_result.status();
305   EXPECT_EQ(backup2_size, next_result.value());
306   EXPECT_EQ(buffer_size, dec_stream->Position());
307   EXPECT_EQ(pt.substr(buffer_size - backup2_size, backup2_size),
308             std::string(reinterpret_cast<const char*>(buffer), backup2_size));
309 
310   // Read the stream to the end.
311   std::string decrypted_rest;
312   auto status = test::ReadFromStream(dec_stream.get(), &decrypted_rest);
313   EXPECT_TRUE(status.ok()) << status;
314   EXPECT_EQ(pt_size, dec_stream->Position());
315   EXPECT_EQ(pt, (decrypted_first_segment + decrypted_rest));
316 }
317 
TEST_F(StreamingAeadDecryptingStreamTest,BackupAndPosition)318 TEST_F(StreamingAeadDecryptingStreamTest, BackupAndPosition) {
319   int pt_segment_size = 555;
320   int pt_size = 2313;
321   int header_size = 33;
322 
323   // Get a decrypting stream.
324   std::string pt = Random::GetRandomBytes(pt_size);
325   DummyStreamSegmentEncrypter seg_enc(pt_segment_size, header_size,
326       /* ct_offset = */ 0);
327   std::string ct = seg_enc.GenerateCiphertext(pt);
328   ValidationRefs refs;
329   auto dec_stream = GetDecryptingStream(pt_segment_size, header_size,
330       /* ct_offset = */ 0, ct, &refs);
331 
332   // The first segment.
333   const void* buffer;
334   auto next_result = dec_stream->Next(&buffer);
335   int buffer_size = pt_segment_size - header_size;
336   EXPECT_TRUE(next_result.ok()) << next_result.status();
337   EXPECT_EQ(buffer_size, next_result.value());
338   EXPECT_EQ(buffer_size, dec_stream->Position());
339   std::string decrypted_first_segment(reinterpret_cast<const char*>(buffer),
340                                       buffer_size);
341 
342   // BackUp several times, but in total fewer bytes than returned by Next().
343   std::vector<int> backup_sizes = {0, 1, 5, 0, 10, 78, -42, 60, 120, -120};
344   int total_backup_size = 0;
345   for (auto backup_size : backup_sizes) {
346     dec_stream->BackUp(backup_size);
347     total_backup_size += std::max(0, backup_size);
348     EXPECT_EQ(buffer_size - total_backup_size, dec_stream->Position());
349   }
350   EXPECT_LT(total_backup_size, next_result.value());
351 
352   // Call Next(), it should succeed (backuped bytes of 1st segment).
353   next_result = dec_stream->Next(&buffer);
354   EXPECT_TRUE(next_result.ok()) << next_result.status();
355   EXPECT_EQ(total_backup_size, next_result.value());
356   EXPECT_EQ(buffer_size, dec_stream->Position());
357 
358   // BackUp() some bytes, again fewer than returned by Next().
359   backup_sizes = {0, 72, -94, 37, 82};
360   total_backup_size = 0;
361   for (auto backup_size : backup_sizes) {
362     dec_stream->BackUp(backup_size);
363     total_backup_size += std::max(0, backup_size);
364     EXPECT_EQ(buffer_size - total_backup_size, dec_stream->Position());
365   }
366   EXPECT_LT(total_backup_size, next_result.value());
367 
368   // Call Next(), it should succeed  (backuped bytes of 1st segment).
369   next_result = dec_stream->Next(&buffer);
370   EXPECT_TRUE(next_result.ok()) << next_result.status();
371   EXPECT_EQ(total_backup_size, next_result.value());
372   EXPECT_EQ(buffer_size, dec_stream->Position());
373 
374   // Call Next() again, it should return a full block (2nd segment).
375   auto prev_position = dec_stream->Position();
376   buffer_size = pt_segment_size;
377   next_result = dec_stream->Next(&buffer);
378   EXPECT_TRUE(next_result.ok()) << next_result.status();
379   EXPECT_EQ(buffer_size, next_result.value());
380   EXPECT_EQ(prev_position + buffer_size, dec_stream->Position());
381 
382   // BackUp a few times, with total over the returned buffer_size.
383   backup_sizes = {0, 72, -100, buffer_size / 2, 200, -25, buffer_size / 2, 42};
384   total_backup_size = 0;
385   for (auto backup_size : backup_sizes) {
386     SCOPED_TRACE(absl::StrCat("backup_size = ", backup_size,
387                               ", total_backup_size = ", total_backup_size));
388     dec_stream->BackUp(backup_size);
389     total_backup_size = std::min(buffer_size,
390                                  total_backup_size + std::max(0, backup_size));
391     EXPECT_EQ(prev_position + buffer_size - total_backup_size,
392               dec_stream->Position());
393   }
394   EXPECT_EQ(total_backup_size, buffer_size);
395   EXPECT_EQ(prev_position, dec_stream->Position());
396 
397   // Call Next() again, it should return a full segment (2nd segment);
398   next_result = dec_stream->Next(&buffer);
399   EXPECT_TRUE(next_result.ok()) << next_result.status();
400   EXPECT_EQ(buffer_size, next_result.value());
401   EXPECT_EQ(prev_position + buffer_size, dec_stream->Position());
402   EXPECT_EQ(2 * pt_segment_size - header_size, dec_stream->Position());
403 
404   // Backup the 2nd segment again, and read the stream to the end.
405   dec_stream->BackUp(buffer_size);
406   EXPECT_EQ(prev_position, dec_stream->Position());
407   std::string decrypted_rest;
408   auto status = test::ReadFromStream(dec_stream.get(), &decrypted_rest);
409   EXPECT_TRUE(status.ok()) << status;
410   EXPECT_EQ(pt_size, dec_stream->Position());
411   EXPECT_EQ(pt, decrypted_first_segment + decrypted_rest);
412 }
413 
414 }  // namespace
415 }  // namespace subtle
416 }  // namespace tink
417 }  // namespace crypto
418