• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.39
/src/tests/test_filters.cpp
1
/*
2
* (C) 2016 Daniel Neus
3
*     2016,2017 Jack Lloyd
4
*     2017 René Korthaus
5
*     2017 Philippe Lieser
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#define BOTAN_NO_DEPRECATED_WARNINGS
11

12
#include "tests.h"
13

14
#if defined(BOTAN_HAS_FILTERS)
15
   #include <botan/data_snk.h>
16
   #include <botan/filters.h>
17
   #include <botan/pipe.h>
18
   #include <botan/internal/secqueue.h>
19
#endif
20

21
#if defined(BOTAN_HAS_PIPE_UNIXFD_IO)
22
   #include <botan/fd_unix.h>
23
   #include <unistd.h>
24
#endif
25

26
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
27
   #include <fstream>
28
#endif
29

30
namespace Botan_Tests {
31

32
#if defined(BOTAN_HAS_FILTERS)
33

34
class Filter_Tests final : public Test {
×
35
   public:
36
      std::vector<Test::Result> run() override {
1✔
37
         std::vector<Test::Result> results;
1✔
38

39
         results.push_back(test_secqueue());
2✔
40
         results.push_back(test_data_src_sink());
2✔
41
         results.push_back(test_data_src_sink_flush());
2✔
42
         results.push_back(test_pipe_io());
2✔
43
         results.push_back(test_pipe_fd_io());
2✔
44
         results.push_back(test_pipe_errors());
2✔
45
         results.push_back(test_pipe_hash());
2✔
46
         results.push_back(test_pipe_mac());
2✔
47
         results.push_back(test_pipe_stream());
2✔
48
         results.push_back(test_pipe_cbc());
2✔
49
         results.push_back(test_pipe_cfb());
2✔
50
         results.push_back(test_pipe_compress());
2✔
51
         results.push_back(test_pipe_compress_bzip2());
2✔
52
         results.push_back(test_pipe_codec());
2✔
53
         results.push_back(test_fork());
2✔
54
         results.push_back(test_chain());
2✔
55
         results.push_back(test_threaded_fork());
2✔
56

57
         return results;
1✔
58
      }
×
59

60
   private:
61
      static Test::Result test_secqueue() {
1✔
62
         Test::Result result("SecureQueue");
1✔
63

64
         try {
1✔
65
            Botan::SecureQueue queue_a;
1✔
66
            result.test_eq("queue not attachable", queue_a.attachable(), false);
1✔
67

68
            std::vector<uint8_t> test_data = {0x24, 0xB2, 0xBF, 0xC2, 0xE6, 0xD4, 0x7E, 0x04, 0x67, 0xB3};
1✔
69
            queue_a.write(test_data.data(), test_data.size());
1✔
70

71
            result.test_eq("size of SecureQueue is correct", queue_a.size(), test_data.size());
1✔
72
            result.test_eq("0 bytes read so far from SecureQueue", queue_a.get_bytes_read(), 0);
1✔
73

74
            uint8_t b;
1✔
75
            result.test_eq("check_available", queue_a.check_available(1), true);
1✔
76
            result.test_eq("check_available", queue_a.check_available(50), false);
1✔
77
            size_t bytes_read = queue_a.read_byte(b);
1✔
78
            result.test_eq("1 byte read", bytes_read, 1);
1✔
79

80
            Botan::secure_vector<uint8_t> produced(b);
1✔
81
            Botan::secure_vector<uint8_t> expected(test_data.at(0));
1✔
82
            result.test_eq("byte read is correct", produced, expected);
1✔
83

84
            result.test_eq("1 bytes read so far from SecureQueue", queue_a.get_bytes_read(), 1);
1✔
85

86
            Botan::SecureQueue queue_b;
1✔
87
            queue_a = queue_b;
1✔
88
            result.test_eq("bytes_read is set correctly", queue_a.get_bytes_read(), 0);
2✔
89
         } catch(std::exception& e) { result.test_failure("SecureQueue", e.what()); }
5✔
90

91
         return result;
1✔
92
      }
×
93

94
      static Test::Result test_data_src_sink() {
1✔
95
         Test::Result result("DataSink");
1✔
96

97
   #if defined(BOTAN_HAS_CODEC_FILTERS)
98
         std::ostringstream oss;
1✔
99

100
         Botan::Pipe pipe(new Botan::Hex_Decoder, new Botan::DataSink_Stream(oss));
1✔
101

102
         Botan::DataSource_Memory input_mem("65666768");
1✔
103
         pipe.process_msg(input_mem);
1✔
104

105
         result.test_eq("output string", oss.str(), "efgh");
3✔
106

107
         Botan::DataSource_Memory input_mem2("41414141");
1✔
108
         pipe.process_msg(input_mem2);
1✔
109

110
         result.test_eq("output string", oss.str(), "efghAAAA");
3✔
111

112
         std::istringstream iss("4343");
1✔
113
         Botan::DataSource_Stream input_strm(iss);
1✔
114
         pipe.process_msg(input_strm);
1✔
115

116
         result.test_eq("output string", oss.str(), "efghAAAACC");
3✔
117
   #endif
118
         return result;
1✔
119
      }
3✔
120

121
      static Test::Result test_data_src_sink_flush() {
1✔
122
         Test::Result result("DataSinkFlush");
1✔
123

124
   #if defined(BOTAN_HAS_CODEC_FILTERS) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
125

126
         const std::string tmp_name = Test::temp_file_name("botan_test_data_src_sink_flush.tmp");
1✔
127
         if(tmp_name.empty()) {
1✔
128
            result.test_failure("Failed to create temporary file");
×
129
            return result;
×
130
         }
131

132
         std::ofstream outfile(tmp_name);
1✔
133

134
         Botan::Pipe pipe(new Botan::Hex_Decoder, new Botan::DataSink_Stream(outfile));
1✔
135

136
         Botan::DataSource_Memory input_mem("65666768");
1✔
137
         pipe.process_msg(input_mem);
1✔
138

139
         std::ifstream outfile_read(tmp_name);
1✔
140
         std::stringstream ss;
1✔
141
         ss << outfile_read.rdbuf();
1✔
142
         std::string foo = ss.str();
1✔
143

144
         result.test_eq("output string", ss.str(), "efgh");
3✔
145

146
         // ensure files are closed
147
         outfile.close();
1✔
148
         outfile_read.close();
1✔
149

150
         if(std::remove(tmp_name.c_str()) != 0) {
1✔
151
            result.test_failure("Failed to remove temporary file at conclusion of test");
×
152
         }
153
   #endif
154
         return result;
1✔
155
      }
3✔
156

157
      static Test::Result test_pipe_io() {
1✔
158
         Test::Result result("Pipe I/O operators");
1✔
159

160
   #if defined(BOTAN_HAS_CODEC_FILTERS)
161
         Botan::Pipe pipe(new Botan::Hex_Encoder);
1✔
162

163
         pipe.process_msg("ABCD");
1✔
164

165
         std::ostringstream oss;
1✔
166
         oss << pipe;
1✔
167
         result.test_eq("output string", oss.str(), "41424344");
3✔
168

169
         std::istringstream iss("AAAA");
1✔
170
         pipe.start_msg();
1✔
171
         iss >> pipe;
1✔
172
         pipe.end_msg();
1✔
173

174
         pipe.set_default_msg(1);
1✔
175
         oss << pipe;
1✔
176
         result.test_eq("output string2", oss.str(), "4142434441414141");
4✔
177
   #endif
178

179
         return result;
1✔
180
      }
1✔
181

182
      static Test::Result test_pipe_errors() {
1✔
183
         Test::Result result("Pipe");
1✔
184

185
         Botan::Pipe pipe;
1✔
186

187
         pipe.append(nullptr);          // ignored
1✔
188
         pipe.append_filter(nullptr);   // ignored
1✔
189
         pipe.prepend(nullptr);         // ignored
1✔
190
         pipe.prepend_filter(nullptr);  // ignored
1✔
191
         pipe.pop();                    // empty pipe, so ignored
1✔
192

193
         auto queue_filter = std::make_shared<Botan::SecureQueue>();
1✔
194

195
         // can't explicitly insert a queue into the pipe because they are implicit
196
         result.test_throws(
3✔
197
            "pipe error", "Pipe::append: SecureQueue cannot be used", [&]() { pipe.append(queue_filter.get()); });
1✔
198

199
         result.test_throws(
3✔
200
            "pipe error", "Pipe::prepend: SecureQueue cannot be used", [&]() { pipe.prepend(queue_filter.get()); });
1✔
201

202
         pipe.append_filter(new Botan::BitBucket);  // succeeds
1✔
203
         pipe.pop();
1✔
204

205
         pipe.prepend_filter(new Botan::BitBucket);  // succeeds
1✔
206
         pipe.pop();
1✔
207

208
         pipe.start_msg();
1✔
209

210
         auto filter = std::make_unique<Botan::BitBucket>();
1✔
211

212
         // now inside a message, cannot modify pipe structure
213

214
         result.test_throws("pipe error", "Cannot call Pipe::append_filter after start_msg", [&]() {
3✔
215
            pipe.append_filter(filter.get());
1✔
216
         });
217

218
         result.test_throws("pipe error", "Cannot call Pipe::prepend_filter after start_msg", [&]() {
3✔
219
            pipe.prepend_filter(filter.get());
1✔
220
         });
221

222
         result.test_throws(
3✔
223
            "pipe error", "Cannot append to a Pipe while it is processing", [&]() { pipe.append(filter.get()); });
1✔
224

225
         result.test_throws(
3✔
226
            "pipe error", "Cannot prepend to a Pipe while it is processing", [&]() { pipe.prepend(filter.get()); });
1✔
227

228
         result.test_throws("pipe error", "Cannot pop off a Pipe while it is processing", [&]() { pipe.pop(); });
4✔
229

230
         pipe.end_msg();
1✔
231

232
         result.test_throws("pipe error", "Cannot call Pipe::append_filter after start_msg", [&]() {
3✔
233
            pipe.append_filter(filter.get());
1✔
234
         });
235

236
         result.test_throws("pipe error", "Cannot call Pipe::prepend_filter after start_msg", [&]() {
3✔
237
            pipe.prepend_filter(filter.get());
1✔
238
         });
239

240
         result.test_throws("pipe error", "Pipe::read: Invalid message number 100", [&]() {
3✔
241
            uint8_t b;
1✔
242
            size_t got = pipe.read(&b, 1, 100);
1✔
243
            BOTAN_UNUSED(got);
×
244
         });
245

246
         pipe.append(nullptr);   // ignored
1✔
247
         pipe.prepend(nullptr);  // ignored
1✔
248
         pipe.pop();             // empty pipe, so ignored
1✔
249

250
         return result;
2✔
251
      }
2✔
252

253
      static Test::Result test_pipe_mac() {
1✔
254
         Test::Result result("Pipe");
1✔
255

256
   #if defined(BOTAN_HAS_CODEC_FILTERS) && defined(BOTAN_HAS_HMAC) && defined(BOTAN_HAS_SHA2_32)
257
         const Botan::SymmetricKey key("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
1✔
258

259
         Botan::Keyed_Filter* mac_filter = new Botan::MAC_Filter("HMAC(SHA-256)", key, 12);
1✔
260

261
         mac_filter->set_iv(Botan::InitializationVector());  // ignored
1✔
262

263
         result.test_throws("Keyed_Filter::set_iv throws if not implemented",
3✔
264
                            "IV length 1 is invalid for HMAC(SHA-256)",
265
                            [mac_filter]() { mac_filter->set_iv(Botan::InitializationVector("AA")); });
1✔
266

267
         Botan::Pipe pipe(mac_filter, new Botan::Base64_Encoder);
1✔
268

269
         pipe.process_msg("Hi");
1✔
270
         pipe.process_msg("Bye");
1✔
271
         pipe.process_msg("Hi");
1✔
272

273
         result.test_eq("MAC 1", pipe.read_all_as_string(0), "e7NoVbtudgU0QiCZ");
3✔
274
         result.test_eq("MAC 2", pipe.read_all_as_string(1), "LhPnfEG+0rk+Ej6y");
3✔
275
         result.test_eq("MAC 3", pipe.read_all_as_string(2), "e7NoVbtudgU0QiCZ");
3✔
276
   #endif
277
         return result;
2✔
278
      }
2✔
279

280
      static Test::Result test_pipe_hash() {
1✔
281
         Test::Result result("Pipe");
1✔
282

283
   #if defined(BOTAN_HAS_SHA2_32)
284
         // unrelated test of popping a chain
285
         Botan::Pipe pipe(new Botan::Chain(new Botan::Hash_Filter("SHA-224"), new Botan::Hash_Filter("SHA-224")));
1✔
286
         pipe.pop();
1✔
287

288
         pipe.append(new Botan::Hash_Filter("SHA-256"));
1✔
289

290
         result.test_eq("Message count", pipe.message_count(), 0);
1✔
291

292
         pipe.start_msg();
1✔
293
         uint8_t inb = 0x41;
1✔
294
         pipe.write(&inb, 1);
1✔
295
         pipe.write(std::vector<uint8_t>(6, 0x41));
2✔
296
         pipe.write(inb);
1✔
297
         pipe.end_msg();
1✔
298

299
         result.test_eq("Message count", pipe.message_count(), 1);
1✔
300
         result.test_eq("Message size", pipe.remaining(), 32);
1✔
301

302
         std::vector<uint8_t> out(32), last16(16);
1✔
303

304
         result.test_eq("Bytes read", pipe.get_bytes_read(0), 0);
1✔
305
         result.test_eq("More to read", pipe.end_of_data(), false);
1✔
306
         result.test_eq("Expected read count", pipe.read(&out[0], 5), 5);
1✔
307
         result.test_eq("Bytes read", pipe.get_bytes_read(0), 5);
1✔
308
         result.test_eq("Peek read", pipe.peek(last16.data(), 18, 11), 16);
1✔
309
         result.test_eq("Expected read count", pipe.read(&out[5], 17), 17);
1✔
310
         result.test_eq("Bytes read", pipe.get_bytes_read(0), 22);
1✔
311
         result.test_eq("Remaining", pipe.remaining(), 10);
1✔
312
         result.test_eq("Remaining", pipe.remaining(), 10);
1✔
313
         result.test_eq("Expected read count", pipe.read(&out[22], 12), 10);
1✔
314
         result.test_eq("Expected read count", pipe.read(&out[0], 1), 0);  // no more output
1✔
315
         result.test_eq("Bytes read", pipe.get_bytes_read(0), 32);
1✔
316
         result.test_eq("No more to read", pipe.end_of_data(), true);
1✔
317

318
         result.test_eq("Expected output", out, "C34AB6ABB7B2BB595BC25C3B388C872FD1D575819A8F55CC689510285E212385");
1✔
319
         result.test_eq("Expected last16", last16, "D1D575819A8F55CC689510285E212385");
1✔
320

321
         pipe.reset();
1✔
322

323
      #if defined(BOTAN_HAS_CRC32)
324
         pipe.prepend(new Botan::Hash_Filter("CRC32"));
1✔
325
         pipe.append(new Botan::Hash_Filter("CRC32"));
1✔
326
         pipe.process_msg(std::vector<uint8_t>(1024, 0));
1✔
327
         result.test_eq("Expected CRC32d", pipe.read_all(1), "99841F60");
2✔
328
      #endif
329
   #endif
330
         return result;
2✔
331
      }
2✔
332

333
      static Test::Result test_pipe_cfb() {
1✔
334
         Test::Result result("Pipe CFB");
1✔
335

336
   #if defined(BOTAN_HAS_BLOWFISH) && defined(BOTAN_HAS_MODE_CFB) && defined(BOTAN_HAS_CODEC_FILTERS)
337

338
         // Generated with Botan 1.10
339

340
         const Botan::InitializationVector iv("AABBCCDDEEFF0123");
1✔
341
         const Botan::SymmetricKey key("AABBCCDDEEFF0123");
1✔
342

343
         const uint8_t msg_bits[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
1✔
344

345
         const std::string cfb_expected[] = {
1✔
346
            "A4",
347
            "BEA4",
348
            "06AD98",
349
            "E4AFC5AC",
350
            "A9B531559C",
351
            "38B60DA66445",
352
            "194F5E93199839",
353
            "093B6381D2E5D806",
354
            "B44FA624226EECF027",
355
            "80B8DC3332A835AC11A8",
356
            "2C0E910A1E5C38344CC5BB",
357
            "3CB6180AE2E189342F681023",
358
            "DE0F4B10C7D9CADDB5A9078199",
359
            "FAE18B0ED873F234CCD6E1555B2D",
360
            "7195FFE735B0A95065BA244C77A11F",
361
         };
16✔
362

363
         Botan::Keyed_Filter* cfb_enc = Botan::get_cipher("Blowfish/CFB", key, iv, Botan::Cipher_Dir::Encryption);
1✔
364
         Botan::Pipe enc_pipe(cfb_enc, new Botan::Hex_Encoder);
1✔
365

366
         Botan::Keyed_Filter* cfb_dec = Botan::get_cipher("Blowfish/CFB", key, Botan::Cipher_Dir::Decryption);
1✔
367
         cfb_dec->set_iv(iv);
1✔
368
         Botan::Pipe dec_pipe(new Botan::Hex_Decoder, cfb_dec, new Botan::Hex_Encoder);
1✔
369

370
         for(size_t i = 1; i != sizeof(msg_bits); ++i) {
15✔
371
            enc_pipe.start_msg();
14✔
372
            enc_pipe.write(msg_bits, i);
14✔
373
            enc_pipe.end_msg();
14✔
374

375
            dec_pipe.process_msg(cfb_expected[i - 1]);
14✔
376
         }
377

378
         result.test_eq("enc pipe msg count", enc_pipe.message_count(), sizeof(msg_bits) - 1);
1✔
379
         result.test_eq("dec pipe msg count", dec_pipe.message_count(), sizeof(msg_bits) - 1);
1✔
380

381
         for(size_t i = 0; i != enc_pipe.message_count(); ++i) {
15✔
382
            result.test_eq("encrypt", enc_pipe.read_all_as_string(i), cfb_expected[i]);
35✔
383
         }
384

385
         for(size_t i = 0; i != dec_pipe.message_count(); ++i) {
15✔
386
            result.test_eq("decrypt", dec_pipe.read_all_as_string(i), Botan::hex_encode(msg_bits, i + 1));
42✔
387
         }
388
   #endif
389

390
         return result;
2✔
391
      }
18✔
392

393
      static Test::Result test_pipe_cbc() {
1✔
394
         Test::Result result("Pipe CBC");
1✔
395

396
   #if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC) && defined(BOTAN_HAS_CIPHER_MODE_PADDING)
397
         Botan::Cipher_Mode_Filter* cipher = new Botan::Cipher_Mode_Filter(
1✔
398
            Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::Cipher_Dir::Encryption));
1✔
399

400
         result.test_eq("Cipher filter name", cipher->name(), "AES-128/CBC/PKCS7");
3✔
401

402
         result.test_eq("Cipher filter nonce size", cipher->valid_iv_length(16), true);
1✔
403
         result.test_eq("Cipher filter nonce size", cipher->valid_iv_length(17), false);
1✔
404

405
         result.test_eq("Cipher key length max", cipher->key_spec().maximum_keylength(), 16);
1✔
406
         result.test_eq("Cipher key length min", cipher->key_spec().minimum_keylength(), 16);
1✔
407

408
         // takes ownership of cipher
409
         Botan::Pipe pipe(cipher);
1✔
410

411
         cipher->set_key(Botan::SymmetricKey("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1✔
412
         cipher->set_iv(Botan::InitializationVector("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1✔
413

414
         pipe.process_msg("Don't use plain CBC mode");
1✔
415

416
         result.test_eq("Message count", pipe.message_count(), 1);
1✔
417
         result.test_eq("Bytes read", pipe.get_bytes_read(), 0);
1✔
418
         auto ciphertext = pipe.read_all();
1✔
419
         result.test_eq("Bytes read after", pipe.get_bytes_read(), ciphertext.size());
1✔
420

421
         result.test_eq("Ciphertext", ciphertext, "9BDD7300E0CB61CA71FFF957A71605DB 6836159C36781246A1ADF50982757F4B");
1✔
422

423
         pipe.process_msg("IV carryover");
1✔
424
         auto ciphertext2 = pipe.read_all(1);
1✔
425
         pipe.process_msg("IV carryover2");
1✔
426
         auto ciphertext3 = pipe.read_all(2);
1✔
427

428
         // These values tested against PyCrypto
429
         result.test_eq("Ciphertext2", ciphertext2, "AA8D682958A4A044735DAC502B274DB2");
1✔
430
         result.test_eq("Ciphertext3", ciphertext3, "1241B9976F73051BCF809525D6E86C25");
1✔
431

432
         Botan::Cipher_Mode_Filter* dec_cipher = new Botan::Cipher_Mode_Filter(
1✔
433
            Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::Cipher_Dir::Decryption));
1✔
434
         pipe.append(dec_cipher);
1✔
435
         dec_cipher->set_key(Botan::SymmetricKey("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1✔
436
         dec_cipher->set_iv(Botan::InitializationVector("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB"));
1✔
437

438
         // reset the IV on the encryption filter
439
         cipher->set_iv(Botan::InitializationVector("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB"));
1✔
440

441
         const std::vector<uint8_t> zeros_in(1024);
1✔
442
         Botan::DataSource_Memory src(zeros_in);
1✔
443
         pipe.start_msg();
1✔
444
         pipe.write(src);
1✔
445
         pipe.end_msg();
1✔
446

447
         pipe.set_default_msg(3);
1✔
448
         result.test_eq("Bytes read", pipe.get_bytes_read(), 0);
1✔
449
         Botan::secure_vector<uint8_t> zeros_out = pipe.read_all();
1✔
450
         result.test_eq("Bytes read", pipe.get_bytes_read(), zeros_out.size());
1✔
451

452
         result.test_eq("Cipher roundtrip", zeros_in, zeros_out);
1✔
453
   #endif
454
         return result;
2✔
455
      }
6✔
456

457
      static Test::Result test_pipe_compress() {
1✔
458
         Test::Result result("Pipe compress zlib");
1✔
459

460
   #if defined(BOTAN_HAS_ZLIB)
461

462
         auto comp_f = std::make_unique<Botan::Compression_Filter>("zlib", 9);
1✔
463

464
         result.test_eq("Compressor filter name", comp_f->name(), "Zlib_Compression");
3✔
465
         Botan::Pipe pipe(comp_f.release());
1✔
466

467
         const std::string input_str = "Hello there HELLO there I said is this thing on?";
1✔
468

469
         pipe.start_msg();
1✔
470
         pipe.write(input_str);
1✔
471
         pipe.end_msg();
1✔
472

473
         auto compr = pipe.read_all(0);
1✔
474
         // Can't do equality check on compression because output may differ
475
         result.test_lt("Compressed is shorter", compr.size(), input_str.size());
1✔
476

477
         auto decomp_f = std::make_unique<Botan::Decompression_Filter>("zlib");
1✔
478
         result.test_eq("Decompressor name", decomp_f->name(), "Zlib_Decompression");
3✔
479
         pipe.append(decomp_f.release());
1✔
480
         pipe.pop();  // remove compressor
1✔
481

482
         pipe.process_msg(compr);
1✔
483

484
         std::string decomp = pipe.read_all_as_string(1);
1✔
485
         result.test_eq("Decompressed ok", decomp, input_str);
1✔
486
   #endif
487

488
         return result;
1✔
489
      }
3✔
490

491
      static Test::Result test_pipe_compress_bzip2() {
1✔
492
         Test::Result result("Pipe compress bzip2");
1✔
493

494
   #if defined(BOTAN_HAS_BZIP2)
495

496
         auto comp_f = std::make_unique<Botan::Compression_Filter>("bzip2", 9);
1✔
497

498
         result.test_eq("Compressor filter name", comp_f->name(), "Bzip2_Compression");
3✔
499
         Botan::Pipe pipe(comp_f.release());
1✔
500

501
         const std::string input_str = "foo\n";
1✔
502

503
         pipe.start_msg();
1✔
504
         pipe.write(input_str);
1✔
505
         pipe.end_msg();
1✔
506

507
         auto compr = pipe.read_all(0);
1✔
508
         // Here the output is actually longer than the input as input is so short
509

510
         auto decomp_f = std::make_unique<Botan::Decompression_Filter>("bzip2");
1✔
511
         result.test_eq("Decompressor name", decomp_f->name(), "Bzip2_Decompression");
3✔
512
         pipe.append(decomp_f.release());
1✔
513
         pipe.pop();  // remove compressor
1✔
514

515
         pipe.process_msg(compr);
1✔
516

517
         std::string decomp = pipe.read_all_as_string(1);
1✔
518
         result.test_eq("Decompressed ok", decomp, input_str);
1✔
519
   #endif
520

521
         return result;
1✔
522
      }
2✔
523

524
      static Test::Result test_pipe_codec() {
1✔
525
         Test::Result result("Pipe");
1✔
526

527
   #if defined(BOTAN_HAS_CODEC_FILTERS)
528
         Botan::Pipe pipe(new Botan::Base64_Encoder);
1✔
529

530
         result.test_eq("Message count", pipe.message_count(), 0);
1✔
531

532
         pipe.process_msg("ABCDX");
1✔
533

534
         result.test_eq("Message count", pipe.message_count(), 1);
1✔
535
         result.test_eq("Message size", pipe.remaining(), 8);
1✔
536

537
         std::string output = pipe.read_all_as_string(0);
1✔
538
         result.test_eq("Message size", pipe.remaining(0), 0);
1✔
539
         result.test_eq("Output round tripped", output, "QUJDRFg=");
2✔
540

541
         pipe.append(new Botan::Base64_Decoder);
1✔
542
         pipe.process_msg("FOOBAZ");
1✔
543

544
         result.test_eq("base64 roundtrip", pipe.read_all_as_string(1), "FOOBAZ");
2✔
545

546
         pipe.pop();
1✔
547
         pipe.pop();
1✔
548

549
         // Pipe is empty of filters, should still pass through
550
         pipe.process_msg("surprise plaintext");
1✔
551

552
         pipe.set_default_msg(2);
1✔
553
         result.test_eq("Message 2", pipe.read_all_as_string(), "surprise plaintext");
3✔
554

555
         pipe.append(new Botan::Hex_Decoder);
1✔
556

557
         pipe.process_msg("F331F00D");
1✔
558
         Botan::secure_vector<uint8_t> bin = pipe.read_all(3);
1✔
559
         result.test_eq("hex decoded", bin, "F331F00D");
1✔
560

561
         pipe.append(new Botan::Hex_Encoder);
1✔
562
         pipe.process_msg("F331F00D");
1✔
563
         result.test_eq("hex roundtrip", pipe.read_all_as_string(4), "F331F00D");
2✔
564

565
         // Now tests with line wrapping enabled
566

567
         pipe.reset();
1✔
568
         pipe.append(new Botan::Hex_Decoder);
1✔
569
         pipe.append(new Botan::Base64_Encoder(/*break_lines=*/true,
1✔
570
                                               /*line_length=*/4,
571
                                               /*trailing_newline=*/true));
1✔
572

573
         pipe.process_msg("6dab1eeb8a2eb69bad");
1✔
574
         result.test_eq(
3✔
575
            "base64 with linebreaks and trailing newline", pipe.read_all_as_string(5), "base\n64ou\ntput\n\n");
2✔
576

577
         pipe.reset();
1✔
578
         pipe.append(new Botan::Hex_Decoder);
1✔
579
         pipe.append(new Botan::Base64_Encoder(true, 5, false));
1✔
580
         pipe.process_msg("6dab1eeb8a2eb69bad");
1✔
581
         result.test_eq("base64 with linebreaks", pipe.read_all_as_string(6), "base6\n4outp\nut\n");
2✔
582

583
         pipe.reset();
1✔
584
         pipe.append(new Botan::Hex_Encoder(true, 13, Botan::Hex_Encoder::Uppercase));
1✔
585
         pipe.process_msg("hex encoding this string");
1✔
586
         result.test_eq("hex uppercase with linebreaks",
3✔
587
                        pipe.read_all_as_string(7),
2✔
588
                        "68657820656E6\n36F64696E6720\n7468697320737\n472696E67\n");
589

590
         pipe.reset();
1✔
591
         pipe.append(new Botan::Hex_Encoder(true, 16, Botan::Hex_Encoder::Lowercase));
1✔
592
         pipe.process_msg("hex encoding this string");
1✔
593
         result.test_eq("hex lowercase with linebreaks",
3✔
594
                        pipe.read_all_as_string(8),
2✔
595
                        "68657820656e636f\n64696e6720746869\n7320737472696e67\n");
596
   #endif
597

598
         return result;
2✔
599
      }
1✔
600

601
      static Test::Result test_pipe_stream() {
1✔
602
         Test::Result result("Pipe CTR");
1✔
603

604
   #if defined(BOTAN_HAS_CTR_BE) && defined(BOTAN_HAS_AES)
605
         Botan::Keyed_Filter* aes = nullptr;
1✔
606
         const Botan::SymmetricKey some_other_key("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE");
1✔
607
         const Botan::SymmetricKey key("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
1✔
608
         const Botan::InitializationVector iv("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
1✔
609
         Botan::Pipe pipe(aes = new Botan::StreamCipher_Filter("CTR-BE(AES-128)", some_other_key));
1✔
610

611
         aes->set_key(key);
1✔
612
         aes->set_iv(iv);
1✔
613

614
         pipe.process_msg("ABCDEF");
1✔
615

616
         result.test_eq("Message count", pipe.message_count(), 1);
1✔
617
         result.test_eq("Ciphertext", pipe.read_all(), "FDFD6238F7C6");
2✔
618

619
         pipe.process_msg("ABCDEF");
1✔
620
         result.test_eq("Ciphertext", pipe.read_all(1), "8E72F1153514");
2✔
621
   #endif
622
         return result;
2✔
623
      }
4✔
624

625
      static Test::Result test_fork() {
1✔
626
         Test::Result result("Filter Fork");
1✔
627

628
   #if defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_SHA2_64)
629
         Botan::Pipe pipe(new Botan::Fork(new Botan::Hash_Filter("SHA-256"), new Botan::Hash_Filter("SHA-512-256")));
1✔
630

631
         result.test_eq("Message count", pipe.message_count(), 0);
1✔
632
         pipe.process_msg("OMG");
1✔
633
         result.test_eq("Message count", pipe.message_count(), 2);
1✔
634

635
         // Test reading out of order
636
         result.test_eq("Hash 2", pipe.read_all(1), "610480FFA82F24F6926544B976FE387878E3D973C03DFD591C2E9896EFB903E0");
2✔
637
         result.test_eq("Hash 1", pipe.read_all(0), "C00862D1C6C1CF7C1B49388306E7B3C1BB79D8D6EC978B41035B556DBB3797DF");
2✔
638
   #endif
639
         return result;
1✔
640
      }
1✔
641

642
      static Test::Result test_chain() {
1✔
643
         Test::Result result("Filter Chain");
1✔
644

645
   #if defined(BOTAN_HAS_CODEC_FILTERS) && defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_SHA2_64)
646

647
         Botan::Filter* filters[2] = {new Botan::Hash_Filter("SHA-256"), new Botan::Hex_Encoder};
1✔
648

649
         auto chain = std::make_unique<Botan::Chain>(filters, 2);
1✔
650

651
         result.test_eq("Chain has a name", chain->name(), "Chain");
2✔
652

653
         auto fork = std::make_unique<Botan::Fork>(
1✔
654
            chain.release(), new Botan::Chain(new Botan::Hash_Filter("SHA-512-256", 19), new Botan::Hex_Encoder));
1✔
655

656
         result.test_eq("Fork has a name", fork->name(), "Fork");
2✔
657
         Botan::Pipe pipe(fork.release());
1✔
658

659
         result.test_eq("Message count", pipe.message_count(), 0);
1✔
660
         pipe.process_msg("OMG");
1✔
661
         result.test_eq("Message count", pipe.message_count(), 2);
1✔
662

663
         result.test_eq(
3✔
664
            "Hash 1", pipe.read_all_as_string(0), "C00862D1C6C1CF7C1B49388306E7B3C1BB79D8D6EC978B41035B556DBB3797DF");
2✔
665
         result.test_eq("Hash 2", pipe.read_all_as_string(1), "610480FFA82F24F6926544B976FE387878E3D9");
3✔
666
   #endif
667

668
         return result;
2✔
669
      }
1✔
670

671
      static Test::Result test_pipe_fd_io() {
1✔
672
         Test::Result result("Pipe file descriptor IO");
1✔
673

674
   #if defined(BOTAN_HAS_PIPE_UNIXFD_IO) && defined(BOTAN_HAS_CODEC_FILTERS)
675
         int fd[2];
1✔
676
         if(::pipe(fd) != 0)
1✔
677
            return result;  // pipe unavailable?
678

679
         Botan::Pipe hex_enc(new Botan::Hex_Encoder);
1✔
680
         Botan::Pipe hex_dec(new Botan::Hex_Decoder);
1✔
681

682
         hex_enc.process_msg("hi chappy");
1✔
683
         fd[1] << hex_enc;
1✔
684
         ::close(fd[1]);
1✔
685

686
         hex_dec.start_msg();
1✔
687
         fd[0] >> hex_dec;
1✔
688
         hex_dec.end_msg();
1✔
689
         ::close(fd[0]);
1✔
690

691
         std::string dec = hex_dec.read_all_as_string();
1✔
692

693
         result.test_eq("IO through Unix pipe works", dec, "hi chappy");
2✔
694
   #endif
695

696
         return result;
1✔
697
      }
1✔
698

699
      static Test::Result test_threaded_fork() {
1✔
700
         Test::Result result("Threaded_Fork");
1✔
701

702
   #if defined(BOTAN_HAS_THREAD_UTILS) && defined(BOTAN_HAS_CODEC_FILTERS) && defined(BOTAN_HAS_SHA2_32)
703
         Botan::Pipe pipe(new Botan::Threaded_Fork(new Botan::Hex_Encoder, new Botan::Base64_Encoder));
1✔
704

705
         result.test_eq("Message count", pipe.message_count(), 0);
1✔
706
         pipe.process_msg("woo");
1✔
707
         result.test_eq("Message count", pipe.message_count(), 2);
1✔
708

709
         // Test reading out of order
710
         result.test_eq("Hash 2", pipe.read_all_as_string(1), "d29v");
2✔
711
         result.test_eq("Hash 1", pipe.read_all_as_string(0), "776F6F");
2✔
712

713
         pipe.reset();
1✔
714

715
         const size_t filter_count = 5;
716
         Botan::Filter* filters[filter_count];
717
         for(size_t i = 0; i != filter_count; ++i) {
6✔
718
            filters[i] = new Botan::Hash_Filter("SHA-256");
5✔
719
         }
720

721
         pipe.append(new Botan::Threaded_Fork(filters, filter_count));
1✔
722

723
         result.test_eq("Message count before start_msg", pipe.message_count(), 2);
1✔
724

725
         pipe.start_msg();
1✔
726
         for(size_t i = 0; i != 919; ++i) {
920✔
727
            std::vector<uint8_t> input(i + 5, static_cast<uint8_t>(i));
919✔
728
            pipe.write(input);
919✔
729
         }
919✔
730
         pipe.end_msg();
1✔
731

732
         result.test_eq("Message count after end_msg", pipe.message_count(), 2 + filter_count);
1✔
733
         for(size_t i = 0; i != filter_count; ++i) {
6✔
734
            result.test_eq("Output " + std::to_string(i),
10✔
735
                           pipe.read_all(2 + i),
10✔
736
                           "327AD8055223F5926693D8BEA40F7B35BDEEB535647DFB93F464E40EA01939A9");
737
         }
738
   #endif
739
         return result;
1✔
740
      }
1✔
741
};
742

743
BOTAN_REGISTER_TEST("filters", "filter", Filter_Tests);
744

745
#endif
746

747
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc