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