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