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

randombit / botan / 26735862306

31 May 2026 11:43PM UTC coverage: 89.37%. Remained the same
26735862306

push

github

web-flow
Merge pull request #5631 from randombit/jack/overflow-checks

Systematically eliminate any possible integer overflows

110295 of 123414 relevant lines covered (89.37%)

11075877.11 hits per line

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

99.02
/src/lib/modes/mode_pad/mode_pad.cpp
1
/*
2
* CBC Padding Methods
3
* (C) 1999-2007,2013,2018,2020 Jack Lloyd
4
* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
5
* (C) 2025 René Meusel, Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/internal/mode_pad.h>
11

12
#include <botan/internal/ct_utils.h>
13
#include <botan/internal/int_utils.h>
14

15
namespace Botan {
16

17
size_t BlockCipherModePaddingMethod::output_length(size_t input_length, size_t block_size) const {
2,367✔
18
   // Round input_length down to a multiple of block_size then add a full block
19
   const size_t full_blocks = input_length - (input_length % block_size);
2,367✔
20
   return add_or_throw(full_blocks, block_size, "Input too large to pad");
2,367✔
21
}
22

23
/**
24
* Get a block cipher padding method by name
25
*/
26
std::unique_ptr<BlockCipherModePaddingMethod> BlockCipherModePaddingMethod::create(std::string_view algo_spec) {
2,430✔
27
   if(algo_spec == "NoPadding") {
2,430✔
28
      return std::make_unique<Null_Padding>();
107✔
29
   }
30

31
   if(algo_spec == "PKCS7") {
2,323✔
32
      return std::make_unique<PKCS7_Padding>();
2,107✔
33
   }
34

35
   if(algo_spec == "OneAndZeros") {
216✔
36
      return std::make_unique<OneAndZeros_Padding>();
180✔
37
   }
38

39
   if(algo_spec == "X9.23") {
36✔
40
      return std::make_unique<ANSI_X923_Padding>();
16✔
41
   }
42

43
   if(algo_spec == "ESP") {
20✔
44
      return std::make_unique<ESP_Padding>();
20✔
45
   }
46

47
   return nullptr;
×
48
}
49

50
void BlockCipherModePaddingMethod::add_padding(std::span<uint8_t> buffer, size_t last_byte_pos, size_t BS) const {
2,102✔
51
   BOTAN_ASSERT_NOMSG(valid_blocksize(BS));
2,102✔
52
   BOTAN_ASSERT_NOMSG(last_byte_pos < BS);
2,102✔
53
   BOTAN_ASSERT_NOMSG(buffer.size() % BS == 0);
2,102✔
54
   BOTAN_ASSERT_NOMSG(buffer.size() >= BS);
2,102✔
55

56
   auto poison = CT::scoped_poison(last_byte_pos, buffer);
2,102✔
57
   apply_padding(buffer.last(BS), last_byte_pos);
2,102✔
58
}
2,102✔
59

60
size_t BlockCipherModePaddingMethod::unpad(std::span<const uint8_t> last_block) const {
4,014✔
61
   if(!valid_blocksize(last_block.size())) {
4,014✔
62
      return last_block.size();
63
   }
64

65
   auto poison = CT::scoped_poison(last_block);
4,014✔
66
   return CT::driveby_unpoison(remove_padding(last_block));
4,014✔
67
}
4,014✔
68

69
/*
70
* Pad with PKCS #7 Method
71
*/
72
void PKCS7_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
1,906✔
73
   /*
74
   Padding format is
75
   01
76
   0202
77
   030303
78
   ...
79
   */
80
   const uint8_t BS = static_cast<uint8_t>(last_block.size());
1,906✔
81
   const uint8_t start_pos = static_cast<uint8_t>(padding_start_pos);
1,906✔
82
   const uint8_t padding_len = BS - start_pos;
1,906✔
83
   for(uint8_t i = 0; i < BS; ++i) {
30,818✔
84
      auto needs_padding = CT::Mask<uint8_t>::is_gte(i, start_pos);
28,912✔
85
      last_block[i] = needs_padding.select(padding_len, last_block[i]);
28,912✔
86
   }
87
}
1,906✔
88

89
/*
90
* Unpad with PKCS #7 Method
91
*/
92
size_t PKCS7_Padding::remove_padding(std::span<const uint8_t> input) const {
2,167✔
93
   const size_t BS = input.size();
2,167✔
94
   const uint8_t last_byte = input.back();
2,167✔
95

96
   /*
97
   The input should == the block size so if the last byte exceeds
98
   that then the padding is certainly invalid
99
   */
100
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, BS);
2,167✔
101

102
   const size_t pad_pos = BS - last_byte;
2,167✔
103

104
   for(size_t i = 0; i != BS - 1; ++i) {
61,619✔
105
      // Does this byte equal the expected pad byte?
106
      const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
59,452✔
107

108
      // Ignore values that are not part of the padding
109
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
59,452✔
110
      bad_input |= in_range & (~pad_eq);
59,452✔
111
   }
112

113
   return bad_input.select(BS, pad_pos);
2,167✔
114
}
115

116
/*
117
* Pad with ANSI X9.23 Method
118
*/
119
void ANSI_X923_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
8✔
120
   /*
121
   Padding format is
122
   01
123
   0002
124
   000003
125
   ...
126
   */
127
   const uint8_t BS = static_cast<uint8_t>(last_block.size());
8✔
128
   const uint8_t start_pos = static_cast<uint8_t>(padding_start_pos);
8✔
129
   const uint8_t padding_len = BS - start_pos;
8✔
130
   for(uint8_t i = 0; i != BS - 1; ++i) {
144✔
131
      auto needs_padding = CT::Mask<uint8_t>::is_gte(i, start_pos);
136✔
132
      last_block[i] = needs_padding.select(0, last_block[i]);
136✔
133
   }
134

135
   last_block.back() = padding_len;
8✔
136
}
8✔
137

138
/*
139
* Unpad with ANSI X9.23 Method
140
*/
141
size_t ANSI_X923_Padding::remove_padding(std::span<const uint8_t> input) const {
269✔
142
   const size_t BS = input.size();
269✔
143
   const size_t last_byte = input.back();
269✔
144

145
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, BS);
269✔
146

147
   const size_t pad_pos = BS - last_byte;
269✔
148

149
   for(size_t i = 0; i != BS - 1; ++i) {
32,841✔
150
      // Ignore values that are not part of the padding
151
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
32,572✔
152
      const auto pad_is_nonzero = CT::Mask<size_t>::expand(input[i]);
32,572✔
153
      bad_input |= pad_is_nonzero & in_range;
32,572✔
154
   }
155

156
   return bad_input.select(BS, pad_pos);
269✔
157
}
158

159
/*
160
* Pad with One and Zeros Method
161
*/
162
void OneAndZeros_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
176✔
163
   /*
164
   Padding format is
165
   80
166
   8000
167
   800000
168
   ...
169
   */
170
   for(size_t i = 0; i != last_block.size(); ++i) {
1,664✔
171
      auto needs_80 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_equal(i, padding_start_pos));
1,488✔
172
      auto needs_00 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gt(i, padding_start_pos));
1,488✔
173
      last_block[i] = needs_00.select(0x00, needs_80.select(0x80, last_block[i]));
1,488✔
174
   }
175
}
176✔
176

177
/*
178
* Unpad with One and Zeros Method
179
*/
180
size_t OneAndZeros_Padding::remove_padding(std::span<const uint8_t> input) const {
1,179✔
181
   const size_t BS = input.size();
1,179✔
182
   auto bad_input = CT::Mask<uint8_t>::cleared();
1,179✔
183
   auto seen_0x80 = CT::Mask<uint8_t>::cleared();
1,179✔
184

185
   size_t pad_pos = BS - 1;
1,179✔
186

187
   for(size_t i = BS; i != 0; --i) {
502,460✔
188
      const auto is_0x80 = CT::Mask<uint8_t>::is_equal(input[i - 1], 0x80);
501,281✔
189
      const auto is_zero = CT::Mask<uint8_t>::is_zero(input[i - 1]);
501,281✔
190

191
      seen_0x80 |= is_0x80;
501,281✔
192
      pad_pos -= seen_0x80.if_not_set_return(1);
501,281✔
193
      bad_input |= ~seen_0x80 & ~is_zero;
501,281✔
194
   }
195
   bad_input |= ~seen_0x80;
1,179✔
196

197
   return CT::Mask<size_t>::expand(bad_input).select(BS, pad_pos);
1,179✔
198
}
199

200
/*
201
* Pad with ESP Padding Method
202
*/
203
void ESP_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
12✔
204
   /*
205
   Padding format is
206
   01
207
   0102
208
   010203
209
   ...
210
   */
211
   const uint8_t BS = static_cast<uint8_t>(last_block.size());
12✔
212
   const uint8_t start_pos = static_cast<uint8_t>(padding_start_pos);
12✔
213

214
   uint8_t pad_ctr = 0x01;
12✔
215
   for(uint8_t i = 0; i != BS; ++i) {
196✔
216
      auto needs_padding = CT::Mask<uint8_t>::is_gte(i, start_pos);
184✔
217
      last_block[i] = needs_padding.select(pad_ctr, last_block[i]);
184✔
218
      pad_ctr = needs_padding.select(pad_ctr + 1, pad_ctr);
219
   }
220
}
12✔
221

222
/*
223
* Unpad with ESP Padding Method
224
*/
225
size_t ESP_Padding::remove_padding(std::span<const uint8_t> input) const {
273✔
226
   const size_t BS = input.size();
273✔
227
   const uint8_t last_byte = input.back();
273✔
228

229
   auto bad_input = CT::Mask<size_t>::is_zero(last_byte) | CT::Mask<size_t>::is_gt(last_byte, BS);
273✔
230

231
   const size_t pad_pos = BS - last_byte;
273✔
232
   for(size_t i = BS - 1; i != 0; --i) {
32,893✔
233
      const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
32,620✔
234
      const auto incrementing = CT::Mask<size_t>::is_equal(input[i - 1], input[i] - 1);
32,620✔
235

236
      bad_input |= CT::Mask<size_t>(in_range) & ~incrementing;
32,620✔
237
   }
238

239
   return bad_input.select(BS, pad_pos);
273✔
240
}
241

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