xref: /aosp_15_r20/external/tink/cc/subtle/streaming_aead_encrypting_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_encrypting_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/output_stream.h"
31 #include "tink/subtle/random.h"
32 #include "tink/subtle/stream_segment_encrypter.h"
33 #include "tink/subtle/test_util.h"
34 #include "tink/util/ostream_output_stream.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37 
38 namespace crypto {
39 namespace tink {
40 namespace subtle {
41 
42 using crypto::tink::OutputStream;
43 using crypto::tink::subtle::test::DummyStreamSegmentEncrypter;
44 using crypto::tink::util::OstreamOutputStream;
45 
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   std::stringbuf* ct_buf;  // buffer that contains the resulting ciphertext
52   DummyStreamSegmentEncrypter* seg_enc;  // segment encrypter
53 };
54 
55 // A helper for creating StreamingAeadEncryptingStream together
56 // with references to internal objects, used for test validation.
GetEncryptingStream(int pt_segment_size,int header_size,int ct_offset,ValidationRefs * refs)57 std::unique_ptr<OutputStream> GetEncryptingStream(
58     int pt_segment_size, int header_size, int ct_offset, ValidationRefs* refs) {
59   // Prepare ciphertext destination stream.
60   auto ct_stream = absl::make_unique<std::stringstream>();
61   // A reference to the ciphertext buffer, for later validation.
62   refs->ct_buf = ct_stream->rdbuf();
63   std::unique_ptr<OutputStream> ct_destination(
64       absl::make_unique<OstreamOutputStream>(std::move(ct_stream)));
65   auto seg_enc = absl::make_unique<DummyStreamSegmentEncrypter>(
66           pt_segment_size, header_size, ct_offset);
67   // A reference to the segment encrypter, for later validation.
68   refs->seg_enc = seg_enc.get();
69   auto enc_stream = std::move(StreamingAeadEncryptingStream::New(
70                                   std::move(seg_enc), std::move(ct_destination))
71                                   .value());
72   EXPECT_EQ(0, enc_stream->Position());
73   return enc_stream;
74 }
75 
76 
77 class StreamingAeadEncryptingStreamTest : public ::testing::Test {
78 };
79 
TEST_F(StreamingAeadEncryptingStreamTest,WritingStreams)80 TEST_F(StreamingAeadEncryptingStreamTest, WritingStreams) {
81   std::vector<int> pt_sizes = {0, 10, 100, 1000, 10000, 100000, 1000000};
82   std::vector<int> pt_segment_sizes = {64, 100, 128, 1000, 1024};
83   std::vector<int> header_sizes = {5, 10, 32};
84   std::vector<int> ct_offsets = {0, 1, 5, 15};
85   for (auto pt_size : pt_sizes) {
86     for (auto pt_segment_size : pt_segment_sizes) {
87       for (auto header_size : header_sizes) {
88         for (auto ct_offset : ct_offsets) {
89           SCOPED_TRACE(absl::StrCat("pt_size = ", pt_size,
90                                     ", pt_segment_size = ", pt_segment_size,
91                                     ", header_size = ", header_size,
92                                     ", ct_offset = ", ct_offset));
93           // Get an encrypting stream.
94           ValidationRefs refs;
95           auto enc_stream = GetEncryptingStream(pt_segment_size, header_size,
96               ct_offset, &refs);
97 
98           // First buffer returned by Next();
99           void* buffer;
100           auto next_result = enc_stream->Next(&buffer);
101           EXPECT_TRUE(next_result.ok()) << next_result.status();
102           int buffer_size = next_result.value();
103           EXPECT_EQ(pt_segment_size - (header_size + ct_offset), buffer_size);
104           EXPECT_EQ(buffer_size, enc_stream->Position());
105 
106           // Backup the entire first buffer.
107           enc_stream->BackUp(buffer_size);
108           EXPECT_EQ(0, enc_stream->Position());
109 
110           // Write plaintext to the stream, and close the stream.
111           std::string pt = Random::GetRandomBytes(pt_size);
112           auto status = test::WriteToStream(enc_stream.get(), pt);
113           EXPECT_TRUE(status.ok()) << status;
114           EXPECT_EQ(enc_stream->Position(), pt.size());
115           EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
116                     refs.ct_buf->str().size());
117           auto exp_ciphertext = refs.seg_enc->GenerateCiphertext(pt);
118           EXPECT_EQ(exp_ciphertext.size(), refs.ct_buf->str().size());
119           EXPECT_EQ(exp_ciphertext, refs.ct_buf->str());
120 
121           // Try closing the stream again.
122           status = enc_stream->Close();
123           EXPECT_FALSE(status.ok());
124           EXPECT_EQ(absl::StatusCode::kFailedPrecondition, status.code());
125         }
126       }
127     }
128   }
129 }
130 
TEST_F(StreamingAeadEncryptingStreamTest,EmptyPlaintext)131 TEST_F(StreamingAeadEncryptingStreamTest, EmptyPlaintext) {
132   int pt_segment_size = 512;
133   int header_size = 64;
134 
135   // Get an encrypting stream.
136   ValidationRefs refs;
137   auto enc_stream = GetEncryptingStream(
138       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
139 
140   // Close the stream.
141   auto close_status = enc_stream->Close();
142   EXPECT_TRUE(close_status.ok()) << close_status;
143   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
144             refs.ct_buf->str().size());
145   // Ciphertext contains only the header and an "empty" first segment.
146   EXPECT_EQ(header_size + DummyStreamSegmentEncrypter::kSegmentTagSize,
147             refs.ct_buf->str().size());
148   // The last segment is marked as such.
149   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
150             refs.ct_buf->str().back());
151 
152   // Try closing the stream again.
153   close_status = enc_stream->Close();
154   EXPECT_FALSE(close_status.ok());
155   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
156 }
157 
TEST_F(StreamingAeadEncryptingStreamTest,EmptyPlaintextWithBackup)158 TEST_F(StreamingAeadEncryptingStreamTest, EmptyPlaintextWithBackup) {
159   int pt_segment_size = 512;
160   int header_size = 64;
161   void* buffer;
162 
163   // Get an encrypting stream.
164   ValidationRefs refs;
165   auto enc_stream = GetEncryptingStream(
166       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
167 
168   // Get the first segment.
169   auto next_result = enc_stream->Next(&buffer);
170   int buffer_size = pt_segment_size - header_size;
171   EXPECT_TRUE(next_result.ok()) << next_result.status();
172   EXPECT_EQ(buffer_size, next_result.value());
173   EXPECT_EQ(buffer_size, enc_stream->Position());
174 
175   // Backup the entire segment, and close the stream.
176   enc_stream->BackUp(buffer_size);
177   EXPECT_EQ(0, enc_stream->Position());
178   auto close_status = enc_stream->Close();
179   EXPECT_TRUE(close_status.ok()) << close_status;
180   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
181             refs.ct_buf->str().size());
182   // Ciphertext contains only the header and an "empty" first segment.
183   EXPECT_EQ(header_size + DummyStreamSegmentEncrypter::kSegmentTagSize,
184             refs.ct_buf->str().size());
185   // The last segment is marked as such.
186   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
187             refs.ct_buf->str().back());
188 
189   // Try closing the stream again.
190   close_status = enc_stream->Close();
191   EXPECT_FALSE(close_status.ok());
192   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
193 }
194 
TEST_F(StreamingAeadEncryptingStreamTest,OneSegmentPlaintext)195 TEST_F(StreamingAeadEncryptingStreamTest, OneSegmentPlaintext) {
196   int pt_segment_size = 512;
197   int header_size = 64;
198   void* buffer;
199 
200   // Get an encrypting stream.
201   ValidationRefs refs;
202   auto enc_stream = GetEncryptingStream(
203       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
204 
205   // Get the first segment, and close the stream.
206   auto next_result = enc_stream->Next(&buffer);
207   int buffer_size = pt_segment_size - header_size;
208   EXPECT_TRUE(next_result.ok()) << next_result.status();
209   EXPECT_EQ(buffer_size, next_result.value());
210   EXPECT_EQ(buffer_size, enc_stream->Position());
211   auto close_status = enc_stream->Close();
212   EXPECT_TRUE(close_status.ok()) << close_status;
213   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
214             refs.ct_buf->str().size());
215   // Ciphertext contains only header and a full first segment.
216   EXPECT_EQ(pt_segment_size + DummyStreamSegmentEncrypter::kSegmentTagSize,
217             refs.ct_buf->str().size());
218   // The last segment is marked as such.
219   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
220             refs.ct_buf->str().back());
221 
222   // Try closing the stream again.
223   close_status = enc_stream->Close();
224   EXPECT_FALSE(close_status.ok());
225   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
226 }
227 
TEST_F(StreamingAeadEncryptingStreamTest,NextAfterBackup)228 TEST_F(StreamingAeadEncryptingStreamTest, NextAfterBackup) {
229   int pt_segment_size = 512;
230   int part1_size = 123;
231   int part2_size = 74;
232   int header_size = 64;
233   void* buffer;
234 
235   // Get an encrypting stream.
236   ValidationRefs refs;
237   auto enc_stream = GetEncryptingStream(
238       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
239 
240   // Get the first segment.
241   auto next_result = enc_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, enc_stream->Position());
246 
247   // Backup so that only part1_size bytes are written.
248   enc_stream->BackUp(buffer_size - part1_size);
249   EXPECT_EQ(part1_size, enc_stream->Position());
250 
251   // Get backed up space.
252   void* backedup_buffer;
253   next_result = enc_stream->Next(&backedup_buffer);
254   EXPECT_TRUE(next_result.ok()) << next_result.status();
255   EXPECT_EQ(buffer_size - part1_size, next_result.value());
256   EXPECT_EQ(reinterpret_cast<uint8_t*>(buffer) + part1_size,
257             reinterpret_cast<uint8_t*>(backedup_buffer));
258 
259   // Backup so again that (part1_size + part2_size) bytes are written.
260   enc_stream->BackUp(buffer_size - (part1_size + part2_size));
261   EXPECT_EQ(part1_size + part2_size, enc_stream->Position());
262 
263   // Get backed up space again.
264   next_result = enc_stream->Next(&backedup_buffer);
265   EXPECT_TRUE(next_result.ok()) << next_result.status();
266   EXPECT_EQ(buffer_size - (part1_size + part2_size), next_result.value());
267   EXPECT_EQ(reinterpret_cast<uint8_t*>(buffer) + part1_size + part2_size,
268             reinterpret_cast<uint8_t*>(backedup_buffer));
269 
270   // Close the stream.
271   auto close_status = enc_stream->Close();
272   EXPECT_TRUE(close_status.ok()) << close_status;
273 }
274 
TEST_F(StreamingAeadEncryptingStreamTest,OneSegmentPlaintextWithBackup)275 TEST_F(StreamingAeadEncryptingStreamTest, OneSegmentPlaintextWithBackup) {
276   int pt_segment_size = 512;
277   int pt_size = 200;
278   int header_size = 64;
279   void* buffer;
280 
281   // Get an encrypting stream.
282   ValidationRefs refs;
283   auto enc_stream = GetEncryptingStream(
284       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
285 
286   // Get the first segment.
287   auto next_result = enc_stream->Next(&buffer);
288   int buffer_size = pt_segment_size - header_size;
289   EXPECT_TRUE(next_result.ok()) << next_result.status();
290   EXPECT_EQ(buffer_size, next_result.value());
291   EXPECT_EQ(buffer_size, enc_stream->Position());
292 
293   // Backup so that only pt_size bytes are written, and close the stream.
294   enc_stream->BackUp(buffer_size - pt_size);
295   EXPECT_EQ(pt_size, enc_stream->Position());
296   auto close_status = enc_stream->Close();
297   EXPECT_TRUE(close_status.ok()) << close_status;
298   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
299             refs.ct_buf->str().size());
300   // Ciphertext contains only the header and partial first segment.
301   EXPECT_EQ(
302       header_size + pt_size + DummyStreamSegmentEncrypter::kSegmentTagSize,
303       refs.ct_buf->str().size());
304   // The last segment is marked as such.
305   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
306             refs.ct_buf->str().back());
307 
308   // Try closing the stream again.
309   close_status = enc_stream->Close();
310   EXPECT_FALSE(close_status.ok());
311   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
312 }
313 
TEST_F(StreamingAeadEncryptingStreamTest,ManySegmentsPlaintext)314 TEST_F(StreamingAeadEncryptingStreamTest, ManySegmentsPlaintext) {
315   int pt_segment_size = 512;
316   int header_size = 64;
317   void* buffer;
318 
319   // Get an encrypting stream.
320   ValidationRefs refs;
321   auto enc_stream = GetEncryptingStream(
322       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
323 
324   int seg_count = 5;
325   // Get the first segment.
326   auto next_result = enc_stream->Next(&buffer);
327   int first_buffer_size = pt_segment_size - header_size;
328   EXPECT_TRUE(next_result.ok()) << next_result.status();
329   EXPECT_EQ(first_buffer_size, next_result.value());
330   EXPECT_EQ(first_buffer_size, enc_stream->Position());
331 
332   // Get remaining segments.
333   for (int i = 1; i < seg_count; i++) {
334     next_result = enc_stream->Next(&buffer);
335     EXPECT_TRUE(next_result.ok()) << next_result.status();
336     EXPECT_EQ(pt_segment_size, next_result.value());
337     EXPECT_EQ(first_buffer_size + i * pt_segment_size, enc_stream->Position());
338   }
339 
340   // Close the stream.
341   auto close_status = enc_stream->Close();
342   EXPECT_TRUE(close_status.ok()) << close_status;
343   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
344             refs.ct_buf->str().size());
345   // Ciphertext contains seg_count full segments.
346   int ct_segment_size =
347       pt_segment_size + DummyStreamSegmentEncrypter::kSegmentTagSize;
348   EXPECT_EQ(refs.seg_enc->get_ciphertext_segment_size(), ct_segment_size);
349   EXPECT_EQ(ct_segment_size * seg_count, refs.ct_buf->str().size());
350   // The last segment is marked as such.
351   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
352             refs.ct_buf->str().back());
353   // The previous segments are marked as not-last ones.
354   for (int i = 1; i < seg_count - 1; i++) {
355     EXPECT_EQ(DummyStreamSegmentEncrypter::kNotLastSegment,
356               refs.ct_buf->str()[(ct_segment_size * i)-1]);
357   }
358 
359   // Try closing the stream again.
360   close_status = enc_stream->Close();
361   EXPECT_FALSE(close_status.ok());
362   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
363 }
364 
TEST_F(StreamingAeadEncryptingStreamTest,ManySegmentsPlaintextWithBackup)365 TEST_F(StreamingAeadEncryptingStreamTest, ManySegmentsPlaintextWithBackup) {
366   int pt_segment_size = 512;
367   int backup_size = 100;
368   int header_size = 64;
369   void* buffer;
370 
371   // Get an encrypting stream.
372   ValidationRefs refs;
373   auto enc_stream = GetEncryptingStream(
374       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
375 
376   int seg_count = 5;
377   // Get the first segment.
378   auto next_result = enc_stream->Next(&buffer);
379   int first_buffer_size = pt_segment_size - header_size;
380   EXPECT_TRUE(next_result.ok()) << next_result.status();
381   EXPECT_EQ(first_buffer_size, next_result.value());
382   EXPECT_EQ(first_buffer_size, enc_stream->Position());
383 
384   // Get remaining segments.
385   for (int i = 1; i < seg_count; i++) {
386     next_result = enc_stream->Next(&buffer);
387     EXPECT_TRUE(next_result.ok()) << next_result.status();
388     EXPECT_EQ(pt_segment_size, next_result.value());
389     EXPECT_EQ(first_buffer_size + i * pt_segment_size, enc_stream->Position());
390   }
391   // Backup part of the last segment, and close the stream.
392   enc_stream->BackUp(backup_size);
393   EXPECT_EQ(first_buffer_size + (seg_count - 1) * pt_segment_size - backup_size,
394             enc_stream->Position());
395   auto close_status = enc_stream->Close();
396   EXPECT_TRUE(close_status.ok()) << close_status;
397   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
398             refs.ct_buf->str().size());
399   // Ciphertext contains seg_count full segments, minus the size of the backup.
400   int ct_segment_size =
401       pt_segment_size + DummyStreamSegmentEncrypter::kSegmentTagSize;
402   EXPECT_EQ(refs.seg_enc->get_ciphertext_segment_size(), ct_segment_size);
403   EXPECT_EQ(ct_segment_size * seg_count - backup_size,
404             refs.ct_buf->str().size());
405   // The last segment is marked as such.
406   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
407             refs.ct_buf->str().back());
408   // The previous segments are marked as not-last ones.
409   for (int i = 1; i < seg_count - 1; i++) {
410     EXPECT_EQ(DummyStreamSegmentEncrypter::kNotLastSegment,
411               refs.ct_buf->str()[(ct_segment_size * i)-1]);
412   }
413 
414   // Try closing the stream again.
415   close_status = enc_stream->Close();
416   EXPECT_FALSE(close_status.ok());
417   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
418 }
419 
TEST_F(StreamingAeadEncryptingStreamTest,ManySegmentsPlaintextWithFullBackup)420 TEST_F(StreamingAeadEncryptingStreamTest, ManySegmentsPlaintextWithFullBackup) {
421   int pt_segment_size = 512;
422   int header_size = 64;
423   void* buffer;
424 
425   // Get an encrypting stream.
426   ValidationRefs refs;
427   auto enc_stream = GetEncryptingStream(
428       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
429 
430   int seg_count = 5;
431   // Get the first segment.
432   auto next_result = enc_stream->Next(&buffer);
433   int first_buffer_size = pt_segment_size - header_size;
434   EXPECT_TRUE(next_result.ok()) << next_result.status();
435   EXPECT_EQ(first_buffer_size, next_result.value());
436   EXPECT_EQ(first_buffer_size, enc_stream->Position());
437 
438   // Get remaining segments.
439   for (int i = 1; i < seg_count; i++) {
440     next_result = enc_stream->Next(&buffer);
441     EXPECT_TRUE(next_result.ok()) << next_result.status();
442     EXPECT_EQ(pt_segment_size, next_result.value());
443     EXPECT_EQ(first_buffer_size + i * pt_segment_size, enc_stream->Position());
444   }
445   // Backup the entire last segment, and close the stream.
446   enc_stream->BackUp(pt_segment_size);
447   EXPECT_EQ(first_buffer_size + (seg_count - 2) * pt_segment_size,
448             enc_stream->Position());
449   auto close_status = enc_stream->Close();
450   EXPECT_TRUE(close_status.ok()) << close_status;
451   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
452             refs.ct_buf->str().size());
453   // Ciphertext contains (seg_count - 1) full segments.
454   int ct_segment_size =
455       pt_segment_size + DummyStreamSegmentEncrypter::kSegmentTagSize;
456   EXPECT_EQ(refs.seg_enc->get_ciphertext_segment_size(), ct_segment_size);
457   EXPECT_EQ(ct_segment_size * (seg_count - 1), refs.ct_buf->str().size());
458   // The last segment is marked as such.
459   EXPECT_EQ(DummyStreamSegmentEncrypter::kLastSegment,
460             refs.ct_buf->str().back());
461   // The previous segments are marked as not-last ones.
462   for (int i = 1; i < seg_count - 1; i++) {
463     EXPECT_EQ(DummyStreamSegmentEncrypter::kNotLastSegment,
464               refs.ct_buf->str()[(ct_segment_size * i)-1]);
465   }
466 
467   // Try closing the stream again.
468   close_status = enc_stream->Close();
469   EXPECT_FALSE(close_status.ok());
470   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
471 }
472 
TEST_F(StreamingAeadEncryptingStreamTest,BackupAndPosition)473 TEST_F(StreamingAeadEncryptingStreamTest, BackupAndPosition) {
474   int pt_segment_size = 512;
475   int header_size = 64;
476   void* buffer;
477 
478   // Get an encrypting stream.
479   ValidationRefs refs;
480   auto enc_stream = GetEncryptingStream(
481       pt_segment_size, header_size, /* ct_offset = */ 0, &refs);
482 
483   // The first buffer.
484   auto next_result = enc_stream->Next(&buffer);
485   int buffer_size = pt_segment_size - header_size;
486   EXPECT_TRUE(next_result.ok()) << next_result.status();
487   EXPECT_EQ(buffer_size, next_result.value());
488   EXPECT_EQ(buffer_size, enc_stream->Position());
489 
490   // BackUp several times, but in total fewer bytes than returned by Next().
491   std::vector<int> backup_sizes = {0, 1, 5, 0, 10, 78, -42, 60, 120, -120};
492   int total_backup_size = 0;
493   for (auto backup_size : backup_sizes) {
494     enc_stream->BackUp(backup_size);
495     total_backup_size += std::max(0, backup_size);
496     EXPECT_EQ(buffer_size - total_backup_size, enc_stream->Position());
497   }
498   EXPECT_LT(total_backup_size, next_result.value());
499 
500   // Call Next(), it should succeed (backuped bytes of 1st segment).
501   next_result = enc_stream->Next(&buffer);
502   EXPECT_TRUE(next_result.ok()) << next_result.status();
503   EXPECT_EQ(total_backup_size, next_result.value());
504   EXPECT_EQ(buffer_size, enc_stream->Position());
505 
506   // BackUp() some bytes, again fewer than returned by Next().
507   backup_sizes = {0, 72, -94, 37, 82};
508   total_backup_size = 0;
509   for (auto backup_size : backup_sizes) {
510     enc_stream->BackUp(backup_size);
511     total_backup_size += std::max(0, backup_size);
512     EXPECT_EQ(buffer_size - total_backup_size, enc_stream->Position());
513   }
514   EXPECT_LT(total_backup_size, next_result.value());
515 
516   // Call Next(), it should succeed  (backuped bytes of 1st segment).
517   next_result = enc_stream->Next(&buffer);
518   EXPECT_TRUE(next_result.ok()) << next_result.status();
519   EXPECT_EQ(total_backup_size, next_result.value());
520   EXPECT_EQ(buffer_size, enc_stream->Position());
521 
522   // Call Next() again, it should return a full segment (2nd segment).
523   auto prev_position = enc_stream->Position();
524   buffer_size = pt_segment_size;
525   next_result = enc_stream->Next(&buffer);
526   EXPECT_TRUE(next_result.ok()) << next_result.status();
527   EXPECT_EQ(buffer_size, next_result.value());
528   EXPECT_EQ(prev_position + buffer_size, enc_stream->Position());
529 
530   // BackUp a few times, with total over the returned buffer_size.
531   backup_sizes = {0, 72, -100, buffer_size / 2, 200, -25, buffer_size / 2, 42};
532   total_backup_size = 0;
533   for (auto backup_size : backup_sizes) {
534     SCOPED_TRACE(absl::StrCat("backup_size = ", backup_size,
535                               ", total_backup_size = ", total_backup_size));
536     enc_stream->BackUp(backup_size);
537     total_backup_size = std::min(buffer_size,
538                                  total_backup_size + std::max(0, backup_size));
539     EXPECT_EQ(prev_position + buffer_size - total_backup_size,
540               enc_stream->Position());
541   }
542   EXPECT_EQ(total_backup_size, buffer_size);
543   EXPECT_EQ(prev_position, enc_stream->Position());
544 
545   // Call Next() again, it should return a full segment (2nd segment);
546   next_result = enc_stream->Next(&buffer);
547   EXPECT_TRUE(next_result.ok()) << next_result.status();
548   EXPECT_EQ(buffer_size, next_result.value());
549   EXPECT_EQ(prev_position + buffer_size, enc_stream->Position());
550   EXPECT_EQ(2 * pt_segment_size - header_size, enc_stream->Position());
551 
552   // Backup the entire segment, and close the stream.
553   enc_stream->BackUp(buffer_size);
554   EXPECT_EQ(pt_segment_size - header_size, enc_stream->Position());
555   auto close_status = enc_stream->Close();
556   EXPECT_TRUE(close_status.ok()) << close_status;
557   EXPECT_EQ(refs.seg_enc->get_generated_output_size(),
558             refs.ct_buf->str().size());
559   // Ciphertext contains 1st segment (with header), and no traces
560   // of the "empty" (backed-up) segment.
561   EXPECT_EQ((pt_segment_size + DummyStreamSegmentEncrypter::kSegmentTagSize),
562             refs.ct_buf->str().size());
563 
564   // Try closing the stream again.
565   close_status = enc_stream->Close();
566   EXPECT_FALSE(close_status.ok());
567   EXPECT_EQ(absl::StatusCode::kFailedPrecondition, close_status.code());
568 }
569 
570 }  // namespace
571 }  // namespace subtle
572 }  // namespace tink
573 }  // namespace crypto
574