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

randombit / botan / 5134090420

31 May 2023 03:12PM UTC coverage: 91.721% (-0.3%) from 91.995%
5134090420

push

github

randombit
Merge GH #3565 Disable noisy/pointless pylint warnings

76048 of 82912 relevant lines covered (91.72%)

11755290.1 hits per line

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

91.15
/src/tests/test_modes.cpp
1
/*
2
* (C) 2014,2015,2017 Jack Lloyd
3
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
4
* (C) 2018 Ribose Inc
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_CIPHER_MODES)
12
   #include <botan/cipher_mode.h>
13
#endif
14

15
namespace Botan_Tests {
16

17
#if defined(BOTAN_HAS_CIPHER_MODES)
18

19
class Cipher_Mode_Tests final : public Text_Based_Test {
×
20
   public:
21
      Cipher_Mode_Tests() : Text_Based_Test("modes", "Key,Nonce,In,Out") {}
3✔
22

23
      std::vector<std::string> possible_providers(const std::string& algo) override {
1,245✔
24
         return provider_filter(Botan::Cipher_Mode::providers(algo));
1,245✔
25
      }
26

27
      Test::Result run_one_test(const std::string& algo, const VarMap& vars) override {
1,245✔
28
         const std::vector<uint8_t> key = vars.get_req_bin("Key");
1,245✔
29
         const std::vector<uint8_t> nonce = vars.get_req_bin("Nonce");
1,245✔
30
         const std::vector<uint8_t> input = vars.get_req_bin("In");
1,245✔
31
         const std::vector<uint8_t> expected = vars.get_req_bin("Out");
1,245✔
32

33
         Test::Result result(algo);
2,490✔
34

35
         const std::vector<std::string> providers = possible_providers(algo);
1,245✔
36

37
         if(providers.empty()) {
1,245✔
38
            result.note_missing("cipher mode " + algo);
×
39
            return result;
×
40
         }
41

42
         for(auto&& provider_ask : providers) {
2,492✔
43
            auto enc = Botan::Cipher_Mode::create(algo, Botan::Cipher_Dir::Encryption, provider_ask);
1,247✔
44

45
            auto dec = Botan::Cipher_Mode::create(algo, Botan::Cipher_Dir::Decryption, provider_ask);
1,247✔
46

47
            if(!enc || !dec) {
1,247✔
48
               if(enc) {
×
49
                  result.test_failure("Provider " + provider_ask + " has encrypt but not decrypt");
×
50
               }
51
               if(dec) {
×
52
                  result.test_failure("Provider " + provider_ask + " has decrypt but not encrypt");
×
53
               }
54
               result.note_missing(algo);
×
55
               return result;
×
56
            }
57

58
            result.test_eq("enc and dec granularity is the same", enc->update_granularity(), dec->update_granularity());
1,247✔
59

60
            result.test_gt("update granularity is non-zero", enc->update_granularity(), 0);
1,247✔
61

62
            result.test_eq(
1,247✔
63
               "enc and dec ideal granularity is the same", enc->ideal_granularity(), dec->ideal_granularity());
1,247✔
64

65
            result.test_gt(
1,247✔
66
               "ideal granularity is at least update granularity", enc->ideal_granularity(), enc->update_granularity());
1,247✔
67

68
            result.confirm("ideal granularity is a multiple of update granularity",
2,494✔
69
                           enc->ideal_granularity() % enc->update_granularity() == 0);
1,247✔
70

71
            try {
1,247✔
72
               test_mode(result, algo, provider_ask, "encryption", *enc, key, nonce, input, expected);
2,494✔
73
            } catch(Botan::Exception& e) {
×
74
               result.test_failure("Encryption tests failed", e.what());
×
75
            }
×
76

77
            try {
1,247✔
78
               test_mode(result, algo, provider_ask, "decryption", *dec, key, nonce, expected, input);
2,494✔
79
            } catch(Botan::Exception& e) {
×
80
               result.test_failure("Decryption tests failed", e.what());
×
81
            }
×
82
         }
2,494✔
83

84
         return result;
85
      }
6,225✔
86

87
   private:
88
      static void test_mode(Test::Result& result,
2,494✔
89
                            const std::string& algo,
90
                            const std::string& provider,
91
                            const std::string& direction,
92
                            Botan::Cipher_Mode& mode,
93
                            const std::vector<uint8_t>& key,
94
                            const std::vector<uint8_t>& nonce,
95
                            const std::vector<uint8_t>& input,
96
                            const std::vector<uint8_t>& expected) {
97
         const bool is_cbc = (algo.find("/CBC") != std::string::npos);
2,494✔
98
         const bool is_ctr = (algo.find("CTR") != std::string::npos);
2,494✔
99

100
         result.test_eq("name", mode.name(), algo);
4,988✔
101

102
         // Some modes report base even if got from another provider
103
         if(mode.provider() != "base") {
2,494✔
104
            result.test_eq("provider", mode.provider(), provider);
×
105
         }
106

107
         result.test_eq("mode not authenticated", mode.authenticated(), false);
2,494✔
108

109
         const size_t update_granularity = mode.update_granularity();
2,494✔
110
         const size_t min_final_bytes = mode.minimum_final_size();
2,494✔
111

112
         // FFI currently requires this, so assure it is true for all modes
113
         result.test_gt("buffer sizes ok", mode.ideal_granularity(), min_final_bytes);
2,494✔
114

115
         result.test_eq("key not set", mode.has_keying_material(), false);
2,494✔
116

117
         result.test_throws("Unkeyed object throws", [&]() {
4,988✔
118
            Botan::secure_vector<uint8_t> bad(update_granularity);
2,494✔
119
            mode.finish(bad);
2,494✔
120
         });
×
121

122
         if(is_cbc) {
2,494✔
123
            // can't test equal due to CBC padding
124

125
            if(direction == "encryption") {
658✔
126
               result.test_lte("output_length", mode.output_length(input.size()), expected.size());
658✔
127
            } else {
128
               result.test_gte("output_length", mode.output_length(input.size()), expected.size());
658✔
129
            }
130
         } else {
131
            // assume all other modes are not expanding (currently true)
132
            result.test_eq("output_length", mode.output_length(input.size()), expected.size());
3,672✔
133
         }
134

135
         result.confirm("default nonce size is allowed", mode.valid_nonce_length(mode.default_nonce_length()));
4,988✔
136

137
         // Test that disallowed nonce sizes result in an exception
138
         static constexpr size_t large_nonce_size = 65000;
2,494✔
139
         result.test_eq("Large nonce not allowed", mode.valid_nonce_length(large_nonce_size), false);
2,494✔
140
         result.test_throws("Large nonce causes exception", [&mode]() { mode.start(nullptr, large_nonce_size); });
7,482✔
141

142
         Botan::secure_vector<uint8_t> garbage = Test::rng().random_vec(update_granularity);
2,494✔
143

144
         // Test to make sure reset() resets what we need it to
145
         result.test_throws("Cannot process data (update) until key is set", [&]() { mode.update(garbage); });
7,482✔
146
         result.test_throws("Cannot process data (finish) until key is set", [&]() { mode.finish(garbage); });
9,976✔
147

148
         mode.set_key(mutate_vec(key));
2,494✔
149

150
         if(is_ctr == false) {
2,494✔
151
            result.test_throws("Cannot process data until nonce is set", [&]() { mode.update(garbage); });
9,944✔
152
         }
153

154
         mode.start(mutate_vec(nonce));
2,494✔
155
         mode.reset();
2,494✔
156

157
         if(is_ctr == false) {
2,494✔
158
            result.test_throws("Cannot process data until nonce is set (after start/reset)",
7,458✔
159
                               [&]() { mode.update(garbage); });
2,486✔
160
         }
161

162
         mode.start(mutate_vec(nonce));
2,494✔
163
         mode.update(garbage);
2,494✔
164

165
         mode.reset();
2,494✔
166

167
         mode.set_key(key);
2,494✔
168
         result.test_eq("key is set", mode.has_keying_material(), true);
2,494✔
169
         mode.start(nonce);
2,494✔
170

171
         Botan::secure_vector<uint8_t> buf;
2,494✔
172

173
         buf.assign(input.begin(), input.end());
2,494✔
174
         mode.finish(buf);
2,494✔
175
         result.test_eq(direction + " all-in-one", buf, expected);
2,494✔
176

177
         // additionally test update() and process() if possible
178
         if(input.size() >= update_granularity + min_final_bytes) {
2,494✔
179
            const size_t max_blocks_to_process = (input.size() - min_final_bytes) / update_granularity;
2,169✔
180
            const size_t bytes_to_process = max_blocks_to_process * update_granularity;
2,169✔
181

182
            // test update, 1 block at a time
183
            if(max_blocks_to_process > 1) {
2,169✔
184
               Botan::secure_vector<uint8_t> block(update_granularity);
1,789✔
185
               buf.clear();
1,789✔
186

187
               mode.start(nonce);
1,789✔
188
               for(size_t i = 0; i != max_blocks_to_process; ++i) {
15,605✔
189
                  block.assign(input.data() + i * update_granularity, input.data() + (i + 1) * update_granularity);
13,816✔
190

191
                  mode.update(block);
13,816✔
192
                  buf += block;
13,816✔
193
               }
194

195
               Botan::secure_vector<uint8_t> last_bits(input.data() + bytes_to_process, input.data() + input.size());
1,789✔
196
               mode.finish(last_bits);
1,789✔
197
               buf += last_bits;
1,789✔
198

199
               result.test_eq(direction + " update-1", buf, expected);
3,578✔
200
            }
3,578✔
201

202
            // test update with maximum length input
203
            buf.assign(input.data(), input.data() + bytes_to_process);
2,169✔
204
            Botan::secure_vector<uint8_t> last_bits(input.data() + bytes_to_process, input.data() + input.size());
2,169✔
205

206
            mode.start(nonce);
2,169✔
207
            mode.update(buf);
2,169✔
208
            mode.finish(last_bits);
2,169✔
209

210
            buf += last_bits;
2,169✔
211

212
            result.test_eq(direction + " update-all", buf, expected);
2,169✔
213

214
            // test process with maximum length input
215
            mode.start(nonce);
2,169✔
216
            buf.assign(input.begin(), input.end());
2,169✔
217

218
            const size_t bytes_written = mode.process(buf.data(), bytes_to_process);
2,169✔
219

220
            result.test_eq("correct number of bytes processed", bytes_written, bytes_to_process);
2,169✔
221

222
            mode.finish(buf, bytes_to_process);
2,169✔
223
            result.test_eq(direction + " process", buf, expected);
4,338✔
224
         }
2,169✔
225

226
         mode.clear();
2,494✔
227
         result.test_eq("key is not set", mode.has_keying_material(), false);
2,494✔
228

229
         result.test_throws("Unkeyed object throws after clear", [&]() {
7,482✔
230
            Botan::secure_vector<uint8_t> bad(update_granularity);
2,494✔
231
            mode.finish(bad);
2,494✔
232
         });
×
233
      }
4,988✔
234
};
235

236
BOTAN_REGISTER_SMOKE_TEST("modes", "cipher_modes", Cipher_Mode_Tests);
237

238
class Cipher_Mode_IV_Carry_Tests final : public Test {
×
239
   public:
240
      std::vector<Test::Result> run() override {
1✔
241
         std::vector<Test::Result> results;
1✔
242
         results.push_back(test_cbc_iv_carry());
2✔
243
         results.push_back(test_cfb_iv_carry());
2✔
244
         results.push_back(test_ctr_iv_carry());
2✔
245
         return results;
1✔
246
      }
×
247

248
   private:
249
      static Test::Result test_cbc_iv_carry() {
1✔
250
         Test::Result result("CBC IV carry");
1✔
251

252
   #if defined(BOTAN_HAS_MODE_CBC) && defined(BOTAN_HAS_AES)
253
         std::unique_ptr<Botan::Cipher_Mode> enc(
1✔
254
            Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::Cipher_Dir::Encryption));
1✔
255
         std::unique_ptr<Botan::Cipher_Mode> dec(
1✔
256
            Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::Cipher_Dir::Decryption));
1✔
257

258
         const std::vector<uint8_t> key(16, 0xAA);
1✔
259
         const std::vector<uint8_t> iv(16, 0xAA);
1✔
260

261
         Botan::secure_vector<uint8_t> msg1 =
1✔
262
            Botan::hex_decode_locked("446F6E27742075736520706C61696E20434243206D6F6465");
1✔
263
         Botan::secure_vector<uint8_t> msg2 = Botan::hex_decode_locked("49562063617272796F766572");
1✔
264
         Botan::secure_vector<uint8_t> msg3 = Botan::hex_decode_locked("49562063617272796F76657232");
1✔
265

266
         enc->set_key(key);
1✔
267
         dec->set_key(key);
1✔
268

269
         enc->start(iv);
1✔
270
         enc->finish(msg1);
1✔
271
         result.test_eq("First ciphertext", msg1, "9BDD7300E0CB61CA71FFF957A71605DB6836159C36781246A1ADF50982757F4B");
1✔
272

273
         enc->start();
1✔
274
         enc->finish(msg2);
1✔
275

276
         result.test_eq("Second ciphertext", msg2, "AA8D682958A4A044735DAC502B274DB2");
1✔
277

278
         enc->start();
1✔
279
         enc->finish(msg3);
1✔
280

281
         result.test_eq("Third ciphertext", msg3, "1241B9976F73051BCF809525D6E86C25");
1✔
282

283
         dec->start(iv);
1✔
284
         dec->finish(msg1);
1✔
285

286
         dec->start();
1✔
287
         dec->finish(msg2);
1✔
288

289
         dec->start();
1✔
290
         dec->finish(msg3);
1✔
291
         result.test_eq("Third plaintext", msg3, "49562063617272796F76657232");
1✔
292

293
   #endif
294
         return result;
1✔
295
      }
7✔
296

297
      static Test::Result test_cfb_iv_carry() {
1✔
298
         Test::Result result("CFB IV carry");
1✔
299
   #if defined(BOTAN_HAS_MODE_CFB) && defined(BOTAN_HAS_AES)
300
         std::unique_ptr<Botan::Cipher_Mode> enc(
1✔
301
            Botan::Cipher_Mode::create("AES-128/CFB(8)", Botan::Cipher_Dir::Encryption));
1✔
302
         std::unique_ptr<Botan::Cipher_Mode> dec(
1✔
303
            Botan::Cipher_Mode::create("AES-128/CFB(8)", Botan::Cipher_Dir::Decryption));
1✔
304

305
         const std::vector<uint8_t> key(16, 0xAA);
1✔
306
         const std::vector<uint8_t> iv(16, 0xAB);
1✔
307

308
         Botan::secure_vector<uint8_t> msg1 = Botan::hex_decode_locked("ABCDEF01234567");
1✔
309
         Botan::secure_vector<uint8_t> msg2 = Botan::hex_decode_locked("0000123456ABCDEF");
1✔
310
         Botan::secure_vector<uint8_t> msg3 = Botan::hex_decode_locked("012345");
1✔
311

312
         enc->set_key(key);
1✔
313
         dec->set_key(key);
1✔
314

315
         enc->start(iv);
1✔
316
         enc->finish(msg1);
1✔
317
         result.test_eq("First ciphertext", msg1, "a51522387c4c9b");
1✔
318

319
         enc->start();
1✔
320
         enc->finish(msg2);
1✔
321

322
         result.test_eq("Second ciphertext", msg2, "105457dc2e0649d4");
1✔
323

324
         enc->start();
1✔
325
         enc->finish(msg3);
1✔
326

327
         result.test_eq("Third ciphertext", msg3, "53bd65");
1✔
328

329
         dec->start(iv);
1✔
330
         dec->finish(msg1);
1✔
331
         result.test_eq("First plaintext", msg1, "ABCDEF01234567");
1✔
332

333
         dec->start();
1✔
334
         dec->finish(msg2);
1✔
335
         result.test_eq("Second plaintext", msg2, "0000123456ABCDEF");
1✔
336

337
         dec->start();
1✔
338
         dec->finish(msg3);
1✔
339
         result.test_eq("Third plaintext", msg3, "012345");
1✔
340
   #endif
341
         return result;
1✔
342
      }
7✔
343

344
      static Test::Result test_ctr_iv_carry() {
1✔
345
         Test::Result result("CTR IV carry");
1✔
346
   #if defined(BOTAN_HAS_CTR_BE) && defined(BOTAN_HAS_AES)
347

348
         std::unique_ptr<Botan::Cipher_Mode> enc(
1✔
349
            Botan::Cipher_Mode::create("AES-128/CTR-BE", Botan::Cipher_Dir::Encryption));
1✔
350
         std::unique_ptr<Botan::Cipher_Mode> dec(
1✔
351
            Botan::Cipher_Mode::create("AES-128/CTR-BE", Botan::Cipher_Dir::Decryption));
1✔
352

353
         const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
1✔
354
         const std::vector<uint8_t> iv = Botan::hex_decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF");
1✔
355

356
         enc->set_key(key);
1✔
357
         dec->set_key(key);
1✔
358

359
         const std::vector<std::string> exp_ciphertext = {
1✔
360
            "EC",
361
            "8CDF",
362
            "739860",
363
            "7CB0F2D2",
364
            "1675EA9EA1",
365
            "E4362B7C3C67",
366
            "73516318A077D7",
367
            "FC5073AE6A2CC378",
368
            "7889374FBEB4C81B17",
369
            "BA6C44E89C399FF0F198C",
370
         };
11✔
371

372
         for(size_t i = 1; i != 10; ++i) {
10✔
373
            if(i == 1) {
9✔
374
               enc->start(iv);
1✔
375
               dec->start(iv);
1✔
376
            } else {
377
               enc->start();
8✔
378
               dec->start();
8✔
379
            }
380

381
            Botan::secure_vector<uint8_t> msg(i, 0);
9✔
382
            enc->finish(msg);
9✔
383

384
            result.test_eq("Ciphertext", msg, exp_ciphertext[i - 1].c_str());
9✔
385

386
            dec->finish(msg);
9✔
387

388
            for(size_t j = 0; j != msg.size(); ++j) {
54✔
389
               result.test_eq("Plaintext zeros", static_cast<size_t>(msg[j]), 0);
90✔
390
            }
391
         }
9✔
392
   #endif
393
         return result;
2✔
394
      }
5✔
395
};
396

397
BOTAN_REGISTER_TEST("modes", "iv_carryover", Cipher_Mode_IV_Carry_Tests);
398

399
#endif
400

401
}  // namespace Botan_Tests
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