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

randombit / botan / 15163992109

21 May 2025 01:49PM UTC coverage: 91.087% (-0.01%) from 91.099%
15163992109

push

github

web-flow
Merge pull request #4873 from reneme/feature/span_in_mode_padding

Use std::span for block cipher padding schemes

96462 of 105901 relevant lines covered (91.09%)

12699117.38 hits per line

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

99.0
/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/exceptn.h>
13
#include <botan/internal/ct_utils.h>
14

15
namespace Botan {
16

17
/**
18
* Get a block cipher padding method by name
19
*/
20
std::unique_ptr<BlockCipherModePaddingMethod> BlockCipherModePaddingMethod::create(std::string_view algo_spec) {
2,699✔
21
   if(algo_spec == "NoPadding") {
2,699✔
22
      return std::make_unique<Null_Padding>();
107✔
23
   }
24

25
   if(algo_spec == "PKCS7") {
2,592✔
26
      return std::make_unique<PKCS7_Padding>();
2,368✔
27
   }
28

29
   if(algo_spec == "OneAndZeros") {
224✔
30
      return std::make_unique<OneAndZeros_Padding>();
188✔
31
   }
32

33
   if(algo_spec == "X9.23") {
36✔
34
      return std::make_unique<ANSI_X923_Padding>();
16✔
35
   }
36

37
   if(algo_spec == "ESP") {
20✔
38
      return std::make_unique<ESP_Padding>();
20✔
39
   }
40

41
   return nullptr;
×
42
}
43

44
void BlockCipherModePaddingMethod::add_padding(std::span<uint8_t> buffer, size_t last_byte_pos, size_t BS) const {
1,764✔
45
   BOTAN_ASSERT_NOMSG(valid_blocksize(BS));
1,764✔
46
   BOTAN_ASSERT_NOMSG(last_byte_pos < BS);
1,764✔
47
   BOTAN_ASSERT_NOMSG(buffer.size() % BS == 0);
1,764✔
48
   BOTAN_ASSERT_NOMSG(buffer.size() >= BS);
1,764✔
49

50
   auto poison = CT::scoped_poison(last_byte_pos, buffer);
1,764✔
51
   apply_padding(buffer.last(BS), last_byte_pos);
1,764✔
52
}
1,764✔
53

54
size_t BlockCipherModePaddingMethod::unpad(std::span<const uint8_t> last_block) const {
3,602✔
55
   if(!valid_blocksize(last_block.size())) {
3,602✔
56
      return last_block.size();
57
   }
58

59
   auto poison = CT::scoped_poison(last_block);
3,602✔
60
   return CT::driveby_unpoison(remove_padding(last_block));
3,602✔
61
}
3,602✔
62

63
/*
64
* Pad with PKCS #7 Method
65
*/
66
void PKCS7_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
1,618✔
67
   /*
68
   Padding format is
69
   01
70
   0202
71
   030303
72
   ...
73
   */
74
   const uint8_t BS = static_cast<uint8_t>(last_block.size());
1,618✔
75
   const uint8_t start_pos = static_cast<uint8_t>(padding_start_pos);
1,618✔
76
   const uint8_t padding_len = BS - start_pos;
1,618✔
77
   for(uint8_t i = 0; i < BS; ++i) {
26,402✔
78
      auto needs_padding = CT::Mask<uint8_t>::is_gte(i, start_pos);
24,784✔
79
      last_block[i] = needs_padding.select(padding_len, last_block[i]);
24,784✔
80
   }
81
}
1,618✔
82

83
/*
84
* Unpad with PKCS #7 Method
85
*/
86
size_t PKCS7_Padding::remove_padding(std::span<const uint8_t> input) const {
1,840✔
87
   const size_t BS = input.size();
1,840✔
88
   const uint8_t last_byte = input.back();
1,840✔
89

90
   /*
91
   The input should == the block size so if the last byte exceeds
92
   that then the padding is certainly invalid
93
   */
94
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, BS);
1,840✔
95

96
   const size_t pad_pos = BS - last_byte;
1,840✔
97

98
   for(size_t i = 0; i != BS - 1; ++i) {
56,867✔
99
      // Does this byte equal the expected pad byte?
100
      const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
55,027✔
101

102
      // Ignore values that are not part of the padding
103
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
55,027✔
104
      bad_input |= in_range & (~pad_eq);
55,027✔
105
   }
106

107
   return bad_input.select(BS, pad_pos);
1,840✔
108
}
109

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

129
   last_block.back() = padding_len;
8✔
130
}
8✔
131

132
/*
133
* Unpad with ANSI X9.23 Method
134
*/
135
size_t ANSI_X923_Padding::remove_padding(std::span<const uint8_t> input) const {
269✔
136
   const size_t BS = input.size();
269✔
137
   const size_t last_byte = input.back();
269✔
138

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

141
   const size_t pad_pos = BS - last_byte;
269✔
142

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

150
   return bad_input.select(BS, pad_pos);
269✔
151
}
152

153
/*
154
* Pad with One and Zeros Method
155
*/
156
void OneAndZeros_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
126✔
157
   /*
158
   Padding format is
159
   80
160
   8000
161
   800000
162
   ...
163
   */
164
   for(size_t i = 0; i != last_block.size(); ++i) {
1,214✔
165
      auto needs_80 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_equal(i, padding_start_pos));
1,088✔
166
      auto needs_00 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gt(i, padding_start_pos));
1,088✔
167
      last_block[i] = needs_00.select(0x00, needs_80.select(0x80, last_block[i]));
1,088✔
168
   }
169
}
126✔
170

171
/*
172
* Unpad with One and Zeros Method
173
*/
174
size_t OneAndZeros_Padding::remove_padding(std::span<const uint8_t> input) const {
1,129✔
175
   const size_t BS = input.size();
1,129✔
176
   auto bad_input = CT::Mask<uint8_t>::cleared();
1,129✔
177
   auto seen_0x80 = CT::Mask<uint8_t>::cleared();
1,129✔
178

179
   size_t pad_pos = BS - 1;
1,129✔
180

181
   for(size_t i = BS; i != 0; --i) {
502,010✔
182
      const auto is_0x80 = CT::Mask<uint8_t>::is_equal(input[i - 1], 0x80);
500,881✔
183
      const auto is_zero = CT::Mask<uint8_t>::is_zero(input[i - 1]);
500,881✔
184

185
      seen_0x80 |= is_0x80;
500,881✔
186
      pad_pos -= seen_0x80.if_not_set_return(1);
500,881✔
187
      bad_input |= ~seen_0x80 & ~is_zero;
500,881✔
188
   }
189
   bad_input |= ~seen_0x80;
1,129✔
190

191
   return CT::Mask<size_t>::expand(bad_input).select(BS, pad_pos);
1,129✔
192
}
193

194
/*
195
* Pad with ESP Padding Method
196
*/
197
void ESP_Padding::apply_padding(std::span<uint8_t> last_block, size_t padding_start_pos) const {
12✔
198
   /*
199
   Padding format is
200
   01
201
   0102
202
   010203
203
   ...
204
   */
205
   const uint8_t BS = static_cast<uint8_t>(last_block.size());
12✔
206
   const uint8_t start_pos = static_cast<uint8_t>(padding_start_pos);
12✔
207

208
   uint8_t pad_ctr = 0x01;
12✔
209
   for(uint8_t i = 0; i != BS; ++i) {
196✔
210
      auto needs_padding = CT::Mask<uint8_t>::is_gte(i, start_pos);
184✔
211
      last_block[i] = needs_padding.select(pad_ctr, last_block[i]);
184✔
212
      pad_ctr = needs_padding.select(pad_ctr + 1, pad_ctr);
184✔
213
   }
214
}
12✔
215

216
/*
217
* Unpad with ESP Padding Method
218
*/
219
size_t ESP_Padding::remove_padding(std::span<const uint8_t> input) const {
273✔
220
   const size_t BS = input.size();
273✔
221
   const uint8_t last_byte = input.back();
273✔
222

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

225
   const size_t pad_pos = BS - last_byte;
273✔
226
   for(size_t i = BS - 1; i != 0; --i) {
32,893✔
227
      const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
32,620✔
228
      const auto incrementing = CT::Mask<size_t>::is_equal(input[i - 1], input[i] - 1);
32,620✔
229

230
      bad_input |= CT::Mask<size_t>(in_range) & ~incrementing;
32,620✔
231
   }
232

233
   return bad_input.select(BS, pad_pos);
273✔
234
}
235

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