• 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

98.04
/src/lib/modes/xts/xts.cpp
1
/*
2
* XTS Mode
3
* (C) 2009,2013,2026 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/internal/xts.h>
10

11
#include <botan/exceptn.h>
12
#include <botan/mem_ops.h>
13
#include <botan/internal/fmt.h>
14
#include <botan/internal/poly_dbl.h>
15

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

20
namespace Botan {
21

22
XTS_Mode::XTS_Mode(std::unique_ptr<BlockCipher> cipher) :
2,822✔
23
      m_cipher(std::move(cipher)),
2,822✔
24
      m_cipher_block_size(m_cipher->block_size()),
2,822✔
25
      m_cipher_parallelism(m_cipher->parallel_bytes()),
2,822✔
26
      m_tweak_blocks(m_cipher_parallelism / m_cipher_block_size) {
2,822✔
27
   if(!poly_double_supported_size(m_cipher_block_size)) {
2,822✔
28
      throw Invalid_Argument(fmt("Cannot use {} with XTS", m_cipher->name()));
×
29
   }
30

31
   m_tweak_cipher = m_cipher->new_object();
2,822✔
32
}
2,822✔
33

34
void XTS_Mode::clear() {
1,672✔
35
   m_cipher->clear();
1,672✔
36
   m_tweak_cipher->clear();
1,672✔
37
   reset();
3,344✔
38
}
1,672✔
39

40
size_t XTS_Mode::update_granularity() const {
5,852✔
41
   return m_cipher_block_size;
5,852✔
42
}
43

44
size_t XTS_Mode::ideal_granularity() const {
5,016✔
45
   return m_cipher_parallelism;
5,016✔
46
}
47

48
void XTS_Mode::reset() {
5,016✔
49
   m_tweak.clear();
5,016✔
50
}
3,344✔
51

52
std::string XTS_Mode::name() const {
3,344✔
53
   return cipher().name() + "/XTS";
6,688✔
54
}
55

56
size_t XTS_Mode::minimum_final_size() const {
16,084✔
57
   return cipher_block_size();
16,084✔
58
}
59

60
Key_Length_Specification XTS_Mode::key_spec() const {
3,658✔
61
   return cipher().key_spec().multiple(2);
3,658✔
62
}
63

64
size_t XTS_Mode::default_nonce_length() const {
1,672✔
65
   return cipher_block_size();
1,672✔
66
}
67

68
bool XTS_Mode::valid_nonce_length(size_t n) const {
17,756✔
69
   return n <= cipher_block_size();
17,756✔
70
}
71

72
bool XTS_Mode::has_keying_material() const {
5,016✔
73
   return m_cipher->has_keying_material() && m_tweak_cipher->has_keying_material();
5,016✔
74
}
75

76
void XTS_Mode::key_schedule(std::span<const uint8_t> key) {
3,658✔
77
   const size_t key_half = key.size() / 2;
3,658✔
78

79
   if(key.size() % 2 == 1 || !m_cipher->valid_keylength(key_half)) {
3,658✔
80
      throw Invalid_Key_Length(name(), key.size());
×
81
   }
82

83
   m_cipher->set_key(key.first(key_half));
3,658✔
84
   m_tweak_cipher->set_key(key.last(key_half));
3,658✔
85
}
3,658✔
86

87
void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
14,412✔
88
   if(!valid_nonce_length(nonce_len)) {
14,412✔
89
      throw Invalid_IV_Length(name(), nonce_len);
3,344✔
90
   }
91

92
   m_tweak.resize(m_cipher_parallelism);
12,740✔
93
   clear_mem(m_tweak.data(), m_tweak.size());
12,740✔
94
   copy_mem(m_tweak.data(), nonce, nonce_len);
12,740✔
95
   m_tweak_cipher->encrypt(m_tweak.data());
12,740✔
96

97
   // Just repeated doubling from first, remaining contents are junk...
98
   xts_compute_tweak_block(m_tweak.data(), m_tweak_cipher->block_size(), tweak_blocks());
12,740✔
99
}
12,740✔
100

101
//static
102
void XTS_Mode::update_tweak_block(uint8_t tweak[], size_t BS, size_t blocks_in_tweak) {
3,576✔
103
#if defined(BOTAN_HAS_MODE_XTS_AVX512_CLMUL)
104
   if(BS == 16 && blocks_in_tweak % 8 == 0 && CPUID::has(CPUID::Feature::AVX512_CLMUL)) {
3,576✔
105
      return update_tweak_block_avx512_clmul(tweak, BS, blocks_in_tweak);
×
106
   }
107
#endif
108

109
   /*
110
   * If we don't have a fast method available, just set the first tweak block to
111
   * the doubling of the last tweak block, and recompute all the rest via
112
   * successive doublings.
113
   */
114
   poly_double_n_le(tweak, &tweak[(blocks_in_tweak - 1) * BS], BS);
3,576✔
115
   xts_compute_tweak_block(tweak, BS, blocks_in_tweak);
3,576✔
116
}
117

118
void XTS_Mode::update_tweak(size_t consumed) {
24,280✔
119
   const size_t BS = m_tweak_cipher->block_size();
24,280✔
120
   const size_t blocks_in_tweak = tweak_blocks();
24,280✔
121

122
   BOTAN_ASSERT_NOMSG(consumed > 0 && consumed <= blocks_in_tweak);
24,280✔
123

124
   if(consumed == blocks_in_tweak) {
24,280✔
125
      // Update all in parallel
126
      update_tweak_block(m_tweak.data(), BS, blocks_in_tweak);
3,576✔
127
   } else {
128
      /*
129
      The last remaining tweaks can just be shifted over
130

131
      This could be a lot better though! We can copy all of the remaining tweaks
132
      and just recompute the last few
133
      */
134
      copy_mem(m_tweak.data(), &m_tweak[(consumed * BS)], BS);
20,704✔
135
      xts_compute_tweak_block(m_tweak.data(), BS, blocks_in_tweak);
20,704✔
136
   }
137
}
24,280✔
138

139
size_t XTS_Encryption::output_length(size_t input_length) const {
836✔
140
   return input_length;
836✔
141
}
142

143
size_t XTS_Encryption::process_msg(uint8_t buf[], size_t sz) {
18,470✔
144
   BOTAN_STATE_CHECK(tweak_set());
18,470✔
145
   const size_t BS = cipher_block_size();
13,454✔
146

147
   BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
13,454✔
148
   size_t blocks = sz / BS;
13,454✔
149

150
   const size_t blocks_in_tweak = tweak_blocks();
13,454✔
151

152
   while(blocks > 0) {
25,594✔
153
      const size_t to_proc = std::min(blocks, blocks_in_tweak);
12,140✔
154
      const size_t proc_bytes = to_proc * BS;
12,140✔
155

156
      xor_buf(buf, tweak(), proc_bytes);
12,140✔
157
      cipher().encrypt_n(buf, buf, to_proc);
12,140✔
158
      xor_buf(buf, tweak(), proc_bytes);
12,140✔
159

160
      buf += proc_bytes;
12,140✔
161
      blocks -= to_proc;
12,140✔
162

163
      update_tweak(to_proc);
12,140✔
164
   }
165

166
   return sz;
13,454✔
167
}
168

169
void XTS_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
7,206✔
170
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
7,206✔
171
   const size_t sz = buffer.size() - offset;
7,206✔
172
   uint8_t* buf = buffer.data() + offset;
7,206✔
173

174
   BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS encrypt");
7,206✔
175

176
   const size_t BS = cipher_block_size();
7,206✔
177

178
   if(sz % BS == 0) {
7,206✔
179
      update(buffer, offset);
2,961✔
180
   } else {
181
      // steal ciphertext
182
      const size_t full_blocks = ((sz / BS) - 1) * BS;
4,245✔
183
      const size_t final_bytes = sz - full_blocks;
4,245✔
184
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
4,245✔
185

186
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
4,245✔
187
      buffer.resize(full_blocks + offset);
4,245✔
188
      update(buffer, offset);
4,245✔
189

190
      xor_buf(last, tweak(), BS);
4,245✔
191
      cipher().encrypt(last);
4,245✔
192
      xor_buf(last, tweak(), BS);
4,245✔
193

194
      for(size_t i = 0; i != final_bytes - BS; ++i) {
33,878✔
195
         last[i] ^= last[i + BS];
29,633✔
196
         last[i + BS] ^= last[i];
29,633✔
197
         last[i] ^= last[i + BS];
29,633✔
198
      }
199

200
      xor_buf(last, tweak() + BS, BS);
4,245✔
201
      cipher().encrypt(last);
4,245✔
202
      xor_buf(last, tweak() + BS, BS);
4,245✔
203

204
      buffer += last;
4,245✔
205
   }
4,245✔
206
}
4,698✔
207

208
size_t XTS_Decryption::output_length(size_t input_length) const {
836✔
209
   return input_length;
836✔
210
}
211

212
size_t XTS_Decryption::process_msg(uint8_t buf[], size_t sz) {
18,470✔
213
   BOTAN_STATE_CHECK(tweak_set());
18,470✔
214
   const size_t BS = cipher_block_size();
13,454✔
215

216
   BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
13,454✔
217
   size_t blocks = sz / BS;
13,454✔
218

219
   const size_t blocks_in_tweak = tweak_blocks();
13,454✔
220

221
   while(blocks > 0) {
25,594✔
222
      const size_t to_proc = std::min(blocks, blocks_in_tweak);
12,140✔
223
      const size_t proc_bytes = to_proc * BS;
12,140✔
224

225
      xor_buf(buf, tweak(), proc_bytes);
12,140✔
226
      cipher().decrypt_n(buf, buf, to_proc);
12,140✔
227
      xor_buf(buf, tweak(), proc_bytes);
12,140✔
228

229
      buf += proc_bytes;
12,140✔
230
      blocks -= to_proc;
12,140✔
231

232
      update_tweak(to_proc);
12,140✔
233
   }
234

235
   return sz;
13,454✔
236
}
237

238
void XTS_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
7,206✔
239
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
7,206✔
240
   const size_t sz = buffer.size() - offset;
7,206✔
241
   uint8_t* buf = buffer.data() + offset;
7,206✔
242

243
   BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS decrypt");
7,206✔
244

245
   const size_t BS = cipher_block_size();
7,206✔
246

247
   if(sz % BS == 0) {
7,206✔
248
      update(buffer, offset);
2,961✔
249
   } else {
250
      // steal ciphertext
251
      const size_t full_blocks = ((sz / BS) - 1) * BS;
4,245✔
252
      const size_t final_bytes = sz - full_blocks;
4,245✔
253
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
4,245✔
254

255
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
4,245✔
256
      buffer.resize(full_blocks + offset);
4,245✔
257
      update(buffer, offset);
4,245✔
258

259
      xor_buf(last, tweak() + BS, BS);
4,245✔
260
      cipher().decrypt(last);
4,245✔
261
      xor_buf(last, tweak() + BS, BS);
4,245✔
262

263
      for(size_t i = 0; i != final_bytes - BS; ++i) {
33,878✔
264
         last[i] ^= last[i + BS];
29,633✔
265
         last[i + BS] ^= last[i];
29,633✔
266
         last[i] ^= last[i + BS];
29,633✔
267
      }
268

269
      xor_buf(last, tweak(), BS);
4,245✔
270
      cipher().decrypt(last);
4,245✔
271
      xor_buf(last, tweak(), BS);
4,245✔
272

273
      buffer += last;
4,245✔
274
   }
4,245✔
275
}
4,698✔
276

277
}  // 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