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

randombit / botan / 25457312714

06 May 2026 07:43PM UTC coverage: 89.331% (-2.3%) from 91.667%
25457312714

push

github

randombit
In TLS 1.3 verification of client certs, check the correct extension for OCSP

This was checking if the client asked us (the server) for OCSP, instead of
checking if we asked the client for OCSP when we sent the CertificateRequest.

107574 of 120422 relevant lines covered (89.33%)

11482758.98 hits per line

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

75.9
/src/lib/stream/chacha/chacha.cpp
1
/*
2
* ChaCha
3
* (C) 2014,2018,2023 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/chacha.h>
9

10
#include <botan/exceptn.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/rotate.h>
14

15
#if defined(BOTAN_HAS_CPUID)
16
   #include <botan/internal/cpuid.h>
17
#endif
18

19
namespace Botan {
20

21
namespace {
22

23
inline void chacha_quarter_round(uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d) {
3,243,120✔
24
   a += b;
3,243,120✔
25
   d ^= a;
3,243,120✔
26
   d = rotl<16>(d);
3,243,120✔
27
   c += d;
3,243,120✔
28
   b ^= c;
3,243,120✔
29
   b = rotl<12>(b);
3,243,120✔
30
   a += b;
3,243,120✔
31
   d ^= a;
3,243,120✔
32
   d = rotl<8>(d);
3,243,120✔
33
   c += d;
3,243,120✔
34
   b ^= c;
3,243,120✔
35
   b = rotl<7>(b);
3,243,120✔
36
}
3,243,120✔
37

38
/*
39
* Generate HChaCha cipher stream (for XChaCha IV setup)
40
*/
41
void hchacha(uint32_t output[8], const uint32_t input[16], size_t rounds) {
40,539✔
42
   BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds");
40,539✔
43

44
   uint32_t x00 = input[0];
40,539✔
45
   uint32_t x01 = input[1];
40,539✔
46
   uint32_t x02 = input[2];
40,539✔
47
   uint32_t x03 = input[3];
40,539✔
48
   uint32_t x04 = input[4];
40,539✔
49
   uint32_t x05 = input[5];
40,539✔
50
   uint32_t x06 = input[6];
40,539✔
51
   uint32_t x07 = input[7];
40,539✔
52
   uint32_t x08 = input[8];
40,539✔
53
   uint32_t x09 = input[9];
40,539✔
54
   uint32_t x10 = input[10];
40,539✔
55
   uint32_t x11 = input[11];
40,539✔
56
   uint32_t x12 = input[12];
40,539✔
57
   uint32_t x13 = input[13];
40,539✔
58
   uint32_t x14 = input[14];
40,539✔
59
   uint32_t x15 = input[15];
40,539✔
60

61
   for(size_t i = 0; i != rounds / 2; ++i) {
445,929✔
62
      chacha_quarter_round(x00, x04, x08, x12);
405,390✔
63
      chacha_quarter_round(x01, x05, x09, x13);
405,390✔
64
      chacha_quarter_round(x02, x06, x10, x14);
405,390✔
65
      chacha_quarter_round(x03, x07, x11, x15);
405,390✔
66

67
      chacha_quarter_round(x00, x05, x10, x15);
405,390✔
68
      chacha_quarter_round(x01, x06, x11, x12);
405,390✔
69
      chacha_quarter_round(x02, x07, x08, x13);
405,390✔
70
      chacha_quarter_round(x03, x04, x09, x14);
405,390✔
71
   }
72

73
   output[0] = x00;
40,539✔
74
   output[1] = x01;
40,539✔
75
   output[2] = x02;
40,539✔
76
   output[3] = x03;
40,539✔
77
   output[4] = x12;
40,539✔
78
   output[5] = x13;
40,539✔
79
   output[6] = x14;
40,539✔
80
   output[7] = x15;
40,539✔
81
}
40,539✔
82

83
}  // namespace
84

85
ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) {
21,318✔
86
   BOTAN_ARG_CHECK(m_rounds == 8 || m_rounds == 12 || m_rounds == 20, "ChaCha only supports 8, 12 or 20 rounds");
21,318✔
87
}
21,318✔
88

89
size_t ChaCha::parallelism() {
22,706✔
90
#if defined(BOTAN_HAS_CHACHA_AVX512)
91
   if(CPUID::has(CPUID::Feature::AVX512)) {
22,706✔
92
      return 16;
93
   }
94
#endif
95

96
#if defined(BOTAN_HAS_CHACHA_AVX2)
97
   if(CPUID::has(CPUID::Feature::AVX2)) {
22,706✔
98
      return 8;
18,636✔
99
   }
100
#endif
101

102
   return 4;
103
}
104

105
std::string ChaCha::provider() const {
325✔
106
#if defined(BOTAN_HAS_CHACHA_AVX512)
107
   if(auto feat = CPUID::check(CPUID::Feature::AVX512)) {
325✔
108
      return *feat;
×
109
   }
×
110
#endif
111

112
#if defined(BOTAN_HAS_CHACHA_AVX2)
113
   if(auto feat = CPUID::check(CPUID::Feature::AVX2)) {
325✔
114
      return *feat;
218✔
115
   }
109✔
116
#endif
117

118
#if defined(BOTAN_HAS_CHACHA_SIMD32)
119
   if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
216✔
120
      return *feat;
432✔
121
   }
216✔
122
#endif
123

124
   return "base";
×
125
}
126

127
void ChaCha::chacha(uint8_t output[], size_t output_blocks, uint32_t state[16], size_t rounds) {
174,458✔
128
   BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds");
174,458✔
129

130
#if defined(BOTAN_HAS_CHACHA_AVX512)
131
   if(CPUID::has(CPUID::Feature::AVX512)) {
174,458✔
132
      while(output_blocks >= 16) {
×
133
         ChaCha::chacha_avx512_x16(output, state, rounds);
×
134
         output += 16 * 64;
×
135
         output_blocks -= 16;
×
136
      }
137
   }
138
#endif
139

140
#if defined(BOTAN_HAS_CHACHA_AVX2)
141
   if(CPUID::has(CPUID::Feature::AVX2)) {
174,458✔
142
      while(output_blocks >= 8) {
290,054✔
143
         ChaCha::chacha_avx2_x8(output, state, rounds);
145,027✔
144
         output += 8 * 64;
145,027✔
145
         output_blocks -= 8;
145,027✔
146
      }
147
   }
148
#endif
149

150
#if defined(BOTAN_HAS_CHACHA_SIMD32)
151
   if(CPUID::has(CPUID::Feature::SIMD_4X32)) {
174,458✔
152
      while(output_blocks >= 4) {
203,889✔
153
         ChaCha::chacha_simd32_x4(output, state, rounds);
29,431✔
154
         output += 4 * 64;
29,431✔
155
         output_blocks -= 4;
29,431✔
156
      }
157
   }
158
#endif
159

160
   // TODO interleave rounds
161
   for(size_t i = 0; i != output_blocks; ++i) {
174,458✔
162
      uint32_t x00 = state[0];
×
163
      uint32_t x01 = state[1];
×
164
      uint32_t x02 = state[2];
×
165
      uint32_t x03 = state[3];
×
166
      uint32_t x04 = state[4];
×
167
      uint32_t x05 = state[5];
×
168
      uint32_t x06 = state[6];
×
169
      uint32_t x07 = state[7];
×
170
      uint32_t x08 = state[8];
×
171
      uint32_t x09 = state[9];
×
172
      uint32_t x10 = state[10];
×
173
      uint32_t x11 = state[11];
×
174
      uint32_t x12 = state[12];
×
175
      uint32_t x13 = state[13];
×
176
      uint32_t x14 = state[14];
×
177
      uint32_t x15 = state[15];
×
178

179
      for(size_t r = 0; r != rounds / 2; ++r) {
×
180
         chacha_quarter_round(x00, x04, x08, x12);
×
181
         chacha_quarter_round(x01, x05, x09, x13);
×
182
         chacha_quarter_round(x02, x06, x10, x14);
×
183
         chacha_quarter_round(x03, x07, x11, x15);
×
184

185
         chacha_quarter_round(x00, x05, x10, x15);
×
186
         chacha_quarter_round(x01, x06, x11, x12);
×
187
         chacha_quarter_round(x02, x07, x08, x13);
×
188
         chacha_quarter_round(x03, x04, x09, x14);
×
189
      }
190

191
      x00 += state[0];
×
192
      x01 += state[1];
×
193
      x02 += state[2];
×
194
      x03 += state[3];
×
195
      x04 += state[4];
×
196
      x05 += state[5];
×
197
      x06 += state[6];
×
198
      x07 += state[7];
×
199
      x08 += state[8];
×
200
      x09 += state[9];
×
201
      x10 += state[10];
×
202
      x11 += state[11];
×
203
      x12 += state[12];
×
204
      x13 += state[13];
×
205
      x14 += state[14];
×
206
      x15 += state[15];
×
207

208
      store_le(x00, output + 64 * i + 4 * 0);
×
209
      store_le(x01, output + 64 * i + 4 * 1);
×
210
      store_le(x02, output + 64 * i + 4 * 2);
×
211
      store_le(x03, output + 64 * i + 4 * 3);
×
212
      store_le(x04, output + 64 * i + 4 * 4);
×
213
      store_le(x05, output + 64 * i + 4 * 5);
×
214
      store_le(x06, output + 64 * i + 4 * 6);
×
215
      store_le(x07, output + 64 * i + 4 * 7);
×
216
      store_le(x08, output + 64 * i + 4 * 8);
×
217
      store_le(x09, output + 64 * i + 4 * 9);
×
218
      store_le(x10, output + 64 * i + 4 * 10);
×
219
      store_le(x11, output + 64 * i + 4 * 11);
×
220
      store_le(x12, output + 64 * i + 4 * 12);
×
221
      store_le(x13, output + 64 * i + 4 * 13);
×
222
      store_le(x14, output + 64 * i + 4 * 14);
×
223
      store_le(x15, output + 64 * i + 4 * 15);
×
224

225
      state[12]++;
×
226
      if(state[12] == 0) {
×
227
         state[13] += 1;
×
228
      }
229
   }
230
}
174,458✔
231

232
/*
233
* Combine cipher stream with message
234
*/
235
void ChaCha::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
525,821✔
236
   assert_key_material_set();
525,821✔
237

238
   while(length >= m_buffer.size() - m_position) {
1,047,277✔
239
      const size_t available = m_buffer.size() - m_position;
6,543✔
240

241
      xor_buf(out, in, &m_buffer[m_position], available);
6,543✔
242
      chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
6,543✔
243

244
      length -= available;
6,543✔
245
      in += available;
6,543✔
246
      out += available;
6,543✔
247
      m_position = 0;
6,543✔
248
   }
249

250
   xor_buf(out, in, &m_buffer[m_position], length);
514,913✔
251

252
   m_position += length;
514,913✔
253
}
514,913✔
254

255
void ChaCha::generate_keystream(uint8_t out[], size_t length) {
198,171✔
256
   assert_key_material_set();
198,171✔
257

258
   while(length >= m_buffer.size() - m_position) {
419,545✔
259
      const size_t available = m_buffer.size() - m_position;
23,203✔
260

261
      // TODO: this could write directly to the output buffer
262
      // instead of bouncing it through m_buffer first
263
      copy_mem(out, &m_buffer[m_position], available);
23,203✔
264
      chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
23,203✔
265

266
      length -= available;
23,203✔
267
      out += available;
23,203✔
268
      m_position = 0;
23,203✔
269
   }
270

271
   copy_mem(out, &m_buffer[m_position], length);
198,171✔
272

273
   m_position += length;
198,171✔
274
}
198,171✔
275

276
void ChaCha::initialize_state() {
143,821✔
277
   static const uint32_t TAU[] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
143,821✔
278

279
   static const uint32_t SIGMA[] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
143,821✔
280

281
   m_state[4] = m_key[0];
143,821✔
282
   m_state[5] = m_key[1];
143,821✔
283
   m_state[6] = m_key[2];
143,821✔
284
   m_state[7] = m_key[3];
143,821✔
285

286
   if(m_key.size() == 4) {
143,821✔
287
      m_state[0] = TAU[0];
210✔
288
      m_state[1] = TAU[1];
210✔
289
      m_state[2] = TAU[2];
210✔
290
      m_state[3] = TAU[3];
210✔
291

292
      m_state[8] = m_key[0];
210✔
293
      m_state[9] = m_key[1];
210✔
294
      m_state[10] = m_key[2];
210✔
295
      m_state[11] = m_key[3];
210✔
296
   } else {
297
      m_state[0] = SIGMA[0];
143,611✔
298
      m_state[1] = SIGMA[1];
143,611✔
299
      m_state[2] = SIGMA[2];
143,611✔
300
      m_state[3] = SIGMA[3];
143,611✔
301

302
      m_state[8] = m_key[4];
143,611✔
303
      m_state[9] = m_key[5];
143,611✔
304
      m_state[10] = m_key[6];
143,611✔
305
      m_state[11] = m_key[7];
143,611✔
306
   }
307

308
   m_state[12] = 0;
143,821✔
309
   m_state[13] = 0;
143,821✔
310
   m_state[14] = 0;
143,821✔
311
   m_state[15] = 0;
143,821✔
312

313
   m_position = 0;
143,821✔
314
}
143,821✔
315

316
bool ChaCha::has_keying_material() const {
894,909✔
317
   return !m_state.empty();
894,909✔
318
}
319

320
size_t ChaCha::buffer_size() const {
324✔
321
   return 64;
324✔
322
}
323

324
/*
325
* ChaCha Key Schedule
326
*/
327
void ChaCha::key_schedule(std::span<const uint8_t> key) {
22,706✔
328
   m_key.resize(key.size() / 4);
22,706✔
329
   load_le<uint32_t>(m_key.data(), key.data(), m_key.size());
22,706✔
330

331
   m_state.resize(16);
22,706✔
332

333
   const size_t chacha_block = 64;
22,706✔
334
   m_buffer.resize(parallelism() * chacha_block);
22,706✔
335

336
   set_iv(nullptr, 0);
22,706✔
337
}
22,706✔
338

339
size_t ChaCha::default_iv_length() const {
648✔
340
   return 24;
648✔
341
}
342

343
Key_Length_Specification ChaCha::key_spec() const {
23,355✔
344
   return Key_Length_Specification(16, 32, 16);
23,355✔
345
}
346

347
std::unique_ptr<StreamCipher> ChaCha::new_object() const {
324✔
348
   return std::make_unique<ChaCha>(m_rounds);
324✔
349
}
350

351
bool ChaCha::valid_iv_length(size_t iv_len) const {
145,118✔
352
   return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24);
973✔
353
}
354

355
void ChaCha::set_iv_bytes(const uint8_t iv[], size_t length) {
144,466✔
356
   assert_key_material_set();
144,466✔
357

358
   if(!valid_iv_length(length)) {
144,145✔
359
      throw Invalid_IV_Length(name(), length);
648✔
360
   }
361

362
   initialize_state();
143,821✔
363

364
   if(length == 0) {
143,821✔
365
      // Treat zero length IV same as an all-zero IV
366
      m_state[14] = 0;
22,709✔
367
      m_state[15] = 0;
22,709✔
368
   } else if(length == 8) {
121,112✔
369
      m_state[14] = load_le<uint32_t>(iv, 0);
323✔
370
      m_state[15] = load_le<uint32_t>(iv, 1);
323✔
371
   } else if(length == 12) {
120,789✔
372
      m_state[13] = load_le<uint32_t>(iv, 0);
80,250✔
373
      m_state[14] = load_le<uint32_t>(iv, 1);
80,250✔
374
      m_state[15] = load_le<uint32_t>(iv, 2);
80,250✔
375
   } else if(length == 24) {
40,539✔
376
      m_state[12] = load_le<uint32_t>(iv, 0);
40,539✔
377
      m_state[13] = load_le<uint32_t>(iv, 1);
40,539✔
378
      m_state[14] = load_le<uint32_t>(iv, 2);
40,539✔
379
      m_state[15] = load_le<uint32_t>(iv, 3);
40,539✔
380

381
      secure_vector<uint32_t> hc(8);
40,539✔
382
      hchacha(hc.data(), m_state.data(), m_rounds);
40,539✔
383

384
      m_state[4] = hc[0];
40,539✔
385
      m_state[5] = hc[1];
40,539✔
386
      m_state[6] = hc[2];
40,539✔
387
      m_state[7] = hc[3];
40,539✔
388
      m_state[8] = hc[4];
40,539✔
389
      m_state[9] = hc[5];
40,539✔
390
      m_state[10] = hc[6];
40,539✔
391
      m_state[11] = hc[7];
40,539✔
392
      m_state[12] = 0;
40,539✔
393
      m_state[13] = 0;
40,539✔
394
      m_state[14] = load_le<uint32_t>(iv, 4);
40,539✔
395
      m_state[15] = load_le<uint32_t>(iv, 5);
40,539✔
396
   }
40,539✔
397

398
   chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
143,821✔
399
   m_position = 0;
143,821✔
400
}
143,821✔
401

402
void ChaCha::clear() {
7,166✔
403
   zap(m_key);
7,166✔
404
   zap(m_state);
7,166✔
405
   zap(m_buffer);
7,166✔
406
   m_position = 0;
7,166✔
407
}
7,166✔
408

409
std::string ChaCha::name() const {
12,851✔
410
   return fmt("ChaCha({})", m_rounds);
12,851✔
411
}
412

413
void ChaCha::seek(uint64_t offset) {
1,215✔
414
   assert_key_material_set();
1,215✔
415

416
   // Find the block offset
417
   const uint64_t counter = offset / 64;
891✔
418

419
   uint8_t out[8];
891✔
420

421
   store_le(counter, out);
891✔
422

423
   m_state[12] = load_le<uint32_t>(out, 0);
891✔
424
   m_state[13] += load_le<uint32_t>(out, 1);
891✔
425

426
   chacha(m_buffer.data(), m_buffer.size() / 64, m_state.data(), m_rounds);
891✔
427
   m_position = offset % 64;
891✔
428
}
891✔
429
}  // namespace Botan
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

© 2026 Coveralls, Inc