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

randombit / botan / 28278764342

26 Jun 2026 01:00PM UTC coverage: 89.352% (-0.002%) from 89.354%
28278764342

push

github

web-flow
Merge pull request #5700 from Rohde-Schwarz/chore/span_in_tls_msgs_and_exts

[std::span] For TLS message and extension parsing and usage

112053 of 125406 relevant lines covered (89.35%)

11047919.25 hits per line

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

91.33
/src/lib/stream/ctr/ctr.cpp
1
/*
2
* Counter mode
3
* (C) 1999-2011,2014 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

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

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

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

19
namespace Botan {
20

21
CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher) :
1,214✔
22
      m_cipher(std::move(cipher)),
1,214✔
23
      m_block_size(m_cipher->block_size()),
1,214✔
24
      m_ctr_size(m_block_size),
1,214✔
25
      m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
1,214✔
26
      m_counter(m_cipher->parallel_bytes()),
2,428✔
27
      m_pad(m_counter.size()),
1,214✔
28
      m_pad_pos(0) {}
2,428✔
29

30
CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher, size_t ctr_size) :
102,443✔
31
      m_cipher(std::move(cipher)),
102,443✔
32
      m_block_size(m_cipher->block_size()),
102,443✔
33
      m_ctr_size(ctr_size),
102,443✔
34
      m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
102,443✔
35
      m_counter(m_cipher->parallel_bytes()),
204,886✔
36
      m_pad(m_counter.size()),
102,443✔
37
      m_pad_pos(0) {
204,886✔
38
   BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, "Invalid CTR-BE counter size");
102,443✔
39
}
102,443✔
40

41
void CTR_BE::clear() {
7,504✔
42
   m_cipher->clear();
7,504✔
43
   zeroise(m_pad);
3,900,320✔
44
   zeroise(m_counter);
7,504✔
45
   zap(m_iv);
7,504✔
46
   m_pad_pos = 0;
7,504✔
47
   m_bytes_remaining = 0;
7,504✔
48
}
7,504✔
49

50
std::optional<uint64_t> CTR_BE::remaining_keystream_bytes() const {
5✔
51
   if(!has_keying_material() || m_ctr_size >= sizeof(uint64_t)) {
5✔
52
      return std::nullopt;
1✔
53
   }
54
   return m_bytes_remaining;
4✔
55
}
56

57
size_t CTR_BE::default_iv_length() const {
3,280✔
58
   return m_block_size;
3,280✔
59
}
60

61
bool CTR_BE::valid_iv_length(size_t iv_len) const {
336,686✔
62
   return (iv_len <= m_block_size);
336,686✔
63
}
64

65
size_t CTR_BE::buffer_size() const {
1,661✔
66
   return m_pad.size();
1,661✔
67
}
68

69
Key_Length_Specification CTR_BE::key_spec() const {
211,153✔
70
   return m_cipher->key_spec();
211,153✔
71
}
72

73
std::unique_ptr<StreamCipher> CTR_BE::new_object() const {
2,440✔
74
   return std::make_unique<CTR_BE>(m_cipher->new_object(), m_ctr_size);
2,440✔
75
}
76

77
bool CTR_BE::has_keying_material() const {
21,043,012✔
78
   return m_cipher->has_keying_material();
21,043,012✔
79
}
80

81
void CTR_BE::key_schedule(std::span<const uint8_t> key) {
107,070✔
82
   m_cipher->set_key(key);
107,070✔
83

84
   // Set a default all-zeros IV
85
   set_iv(nullptr, 0);
107,070✔
86
}
107,070✔
87

88
std::string CTR_BE::name() const {
13,459✔
89
   if(m_ctr_size == m_block_size) {
13,459✔
90
      return fmt("CTR-BE({})", m_cipher->name());
13,065✔
91
   } else {
92
      return fmt("CTR-BE({},{})", m_cipher->name(), m_ctr_size);
394✔
93
   }
94
}
95

96
void CTR_BE::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
138,537✔
97
   assert_key_material_set();
138,537✔
98

99
   if(m_ctr_size < sizeof(uint64_t)) {
135,241✔
100
      if(length > m_bytes_remaining) {
112,359✔
101
         throw Invalid_State(fmt("CTR_BE with {}-byte counter has exhausted its keystream", m_ctr_size));
1✔
102
      }
103
      m_bytes_remaining -= length;
112,358✔
104
   }
105

106
   const uint8_t* pad_bits = m_pad.data();
135,240✔
107
   const size_t pad_size = m_pad.size();
135,240✔
108

109
   /* Consume any already computed keystream in m_pad */
110

111
   if(m_pad_pos > 0) {
135,240✔
112
      const size_t avail = pad_size - m_pad_pos;
107,961✔
113
      const size_t take = std::min(length, avail);
107,961✔
114
      xor_buf(out, in, pad_bits + m_pad_pos, take);
107,961✔
115
      length -= take;
107,961✔
116
      in += take;
107,961✔
117
      out += take;
107,961✔
118
      m_pad_pos += take;
107,961✔
119

120
      if(take == avail) {
107,961✔
121
         add_counter(m_ctr_blocks);
2,730✔
122
         m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
2,730✔
123
         m_pad_pos = 0;
2,730✔
124
      }
125
   }
126

127
   /* Bulk processing */
128

129
   [[maybe_unused]] const bool can_use_bs16_ctr4_fastpath = m_block_size == 16 && m_ctr_size == 4 && pad_size % 64 == 0;
135,240✔
130

131
#if defined(BOTAN_HAS_CTR_BE_AVX2)
132
   if(length >= pad_size && can_use_bs16_ctr4_fastpath && CPUID::has(CPUID::Feature::AVX2)) {
135,240✔
133
      const size_t consumed = ctr_proc_bs16_ctr4_avx2(in, out, length);
1,457✔
134
      in += consumed;
1,457✔
135
      out += consumed;
1,457✔
136
      length -= consumed;
1,457✔
137
   }
138
#endif
139

140
#if defined(BOTAN_HAS_CTR_BE_SIMD32)
141
   if(length >= pad_size && can_use_bs16_ctr4_fastpath && CPUID::has(CPUID::Feature::SIMD_4X32)) {
135,240✔
142
      const size_t consumed = ctr_proc_bs16_ctr4_simd32(in, out, length);
6✔
143
      in += consumed;
6✔
144
      out += consumed;
6✔
145
      length -= consumed;
6✔
146
   }
147
#endif
148

149
   while(length >= pad_size) {
135,398✔
150
      xor_buf(out, in, pad_bits, pad_size);
158✔
151
      length -= pad_size;
158✔
152
      in += pad_size;
158✔
153
      out += pad_size;
158✔
154

155
      add_counter(m_ctr_blocks);
158✔
156
      m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
158✔
157
   }
158

159
   /* Now if length > 0 then we have some remaining text, and m_pad is full - consume as required */
160
   if(length > 0) {
135,240✔
161
      xor_buf(out, in, pad_bits, length);
29,343✔
162
      m_pad_pos = length;
29,343✔
163
   }
164
}
135,240✔
165

166
void CTR_BE::generate_keystream(uint8_t out[], size_t length) {
20,649,074✔
167
   assert_key_material_set();
20,649,074✔
168

169
   if(m_ctr_size < sizeof(uint64_t)) {
20,649,074✔
170
      if(length > m_bytes_remaining) {
33✔
171
         throw Invalid_State(fmt("CTR_BE with {}-byte counter has exhausted its keystream", m_ctr_size));
×
172
      }
173
      m_bytes_remaining -= length;
33✔
174
   }
175

176
   const size_t avail = m_pad.size() - m_pad_pos;
20,649,074✔
177
   const size_t take = std::min(length, avail);
20,649,074✔
178
   copy_mem(out, &m_pad[m_pad_pos], take);
20,649,074✔
179
   length -= take;
20,649,074✔
180
   out += take;
20,649,074✔
181
   m_pad_pos += take;
20,649,074✔
182

183
   while(length >= m_pad.size()) {
20,649,074✔
184
      add_counter(m_ctr_blocks);
×
185
      m_cipher->encrypt_n(m_counter.data(), out, m_ctr_blocks);
×
186

187
      length -= m_pad.size();
×
188
      out += m_pad.size();
×
189
   }
190

191
   if(m_pad_pos == m_pad.size()) {
20,649,074✔
192
      add_counter(m_ctr_blocks);
83,050✔
193
      m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
83,050✔
194
      m_pad_pos = 0;
83,050✔
195
   }
196

197
   copy_mem(out, m_pad.data(), length);
20,649,074✔
198
   m_pad_pos += length;
20,649,074✔
199
   BOTAN_ASSERT_NOMSG(m_pad_pos < m_pad.size());
20,649,074✔
200
}
20,649,074✔
201

202
void CTR_BE::set_iv_bytes(const uint8_t iv[], size_t iv_len) {
237,293✔
203
   if(!valid_iv_length(iv_len)) {
237,293✔
204
      throw Invalid_IV_Length(name(), iv_len);
3,288✔
205
   }
206

207
   m_iv.resize(m_block_size);
235,649✔
208
   zeroise(m_iv);
235,649✔
209
   copy_mem(m_iv.data(), iv, iv_len);
235,649✔
210

211
   seek(0);
235,649✔
212
}
233,695✔
213

214
void CTR_BE::add_counter(const uint64_t counter) {
85,977✔
215
   const size_t ctr_size = m_ctr_size;
85,977✔
216
   const size_t ctr_blocks = m_ctr_blocks;
85,977✔
217
   const size_t BS = m_block_size;
85,977✔
218

219
   if(ctr_size == 4) {
85,977✔
220
      const size_t off = (BS - 4);
2,713✔
221
      const uint32_t low32 = static_cast<uint32_t>(counter + load_be<uint32_t>(&m_counter[off], 0));
2,713✔
222

223
      for(size_t i = 0; i != ctr_blocks; ++i) {
65,761✔
224
         store_be(uint32_t(low32 + i), &m_counter[i * BS + off]);
63,048✔
225
      }
226
   } else if(ctr_size == 8) {
83,264✔
227
      const size_t off = (BS - 8);
41✔
228
      const uint64_t low64 = counter + load_be<uint64_t>(&m_counter[off], 0);
41✔
229

230
      for(size_t i = 0; i != ctr_blocks; ++i) {
1,673✔
231
         store_be(uint64_t(low64 + i), &m_counter[i * BS + off]);
1,632✔
232
      }
233
   } else if(ctr_size == 16) {
83,223✔
234
      const size_t off = (BS - 16);
83,223✔
235
      uint64_t b0 = load_be<uint64_t>(&m_counter[off], 0);
83,223✔
236
      uint64_t b1 = load_be<uint64_t>(&m_counter[off], 1);
83,223✔
237
      b1 += counter;
83,223✔
238
      b0 += (b1 < counter) ? 1 : 0;  // carry
83,223✔
239

240
      for(size_t i = 0; i != ctr_blocks; ++i) {
2,746,359✔
241
         store_be(b0, &m_counter[i * BS + off]);
2,663,136✔
242
         store_be(b1, &m_counter[i * BS + off + 8]);
2,663,136✔
243
         b1 += 1;
2,663,136✔
244
         if(b1 == 0) {
2,663,136✔
245
            b0 += 1;  // carry
×
246
         }
247
      }
248
   } else {
249
      for(size_t i = 0; i != ctr_blocks; ++i) {
×
250
         uint64_t local_counter = counter;
×
251
         uint16_t carry = static_cast<uint8_t>(local_counter);
×
252
         for(size_t j = 0; (carry > 0 || local_counter > 0) && j != ctr_size; ++j) {
×
253
            const size_t off = i * BS + (BS - 1 - j);
×
254
            const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry;
×
255
            m_counter[off] = static_cast<uint8_t>(cnt);
×
256
            local_counter = (local_counter >> 8);
×
257
            carry = (cnt >> 8) + static_cast<uint8_t>(local_counter);
×
258
         }
259
      }
260
   }
261
}
85,977✔
262

263
void CTR_BE::seek(uint64_t offset) {
243,693✔
264
   assert_key_material_set();
243,693✔
265

266
   if(m_ctr_size < sizeof(uint64_t)) {
240,099✔
267
      const uint64_t requested_block = offset / m_block_size;
20,702✔
268
      const uint64_t max_blocks = uint64_t{1} << (8 * m_ctr_size);
20,702✔
269
      if(requested_block >= max_blocks) {
20,702✔
270
         throw Invalid_Argument(fmt("CTR_BE::seek offset {} exceeds {}-byte counter range", offset, m_ctr_size));
2✔
271
      }
272

273
      m_bytes_remaining = max_blocks * m_block_size - offset;
20,701✔
274
   }
275

276
   const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size());
240,098✔
277

278
   zeroise(m_counter);
240,098✔
279
   BOTAN_ASSERT_NOMSG(m_counter.size() >= m_iv.size());
240,098✔
280
   copy_mem(m_counter.data(), m_iv.data(), m_iv.size());
240,098✔
281

282
   const size_t BS = m_block_size;
240,098✔
283

284
   // Set m_counter blocks to IV, IV + 1, ... IV + n
285

286
   if(m_ctr_size == 4 && BS >= 8) {
240,098✔
287
      const uint32_t low32 = load_be<uint32_t>(&m_counter[BS - 4], 0);
20,673✔
288

289
      if(m_ctr_blocks >= 4 && is_power_of_2(m_ctr_blocks)) {
20,673✔
290
         size_t written = 1;
291
         while(written < m_ctr_blocks) {
121,152✔
292
            copy_mem(&m_counter[written * BS], &m_counter[0], BS * written);  // NOLINT(*container-data-pointer)
100,479✔
293
            written *= 2;
100,479✔
294
         }
295
      } else {
296
         for(size_t i = 1; i != m_ctr_blocks; ++i) {
×
297
            copy_mem(&m_counter[i * BS], &m_counter[0], BS - 4);  // NOLINT(*container-data-pointer)
×
298
         }
299
      }
300

301
      for(size_t i = 1; i != m_ctr_blocks; ++i) {
631,256✔
302
         const uint32_t c = static_cast<uint32_t>(low32 + i);
610,583✔
303
         store_be(c, &m_counter[(BS - 4) + i * BS]);
610,583✔
304
      }
305
   } else {
306
      // do everything sequentially:
307
      for(size_t i = 1; i != m_ctr_blocks; ++i) {
7,510,548✔
308
         copy_mem(&m_counter[i * BS], &m_counter[(i - 1) * BS], BS);
7,291,123✔
309

310
         for(size_t j = 0; j != m_ctr_size; ++j) {
7,300,613✔
311
            uint8_t& c = m_counter[i * BS + (BS - 1 - j)];
7,300,551✔
312
            c += 1;
7,300,551✔
313
            if(c > 0) {
7,300,551✔
314
               break;
315
            }
316
         }
317
      }
318
   }
319

320
   if(base_counter > 0) {
240,098✔
321
      add_counter(base_counter);
39✔
322
   }
323

324
   m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
240,098✔
325
   m_pad_pos = offset % m_counter.size();
240,098✔
326
}
240,098✔
327
}  // 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