Botan 3.4.0
Crypto and TLS for C&
mode_pad.cpp
Go to the documentation of this file.
1/*
2* CBC Padding Methods
3* (C) 1999-2007,2013,2018,2020 Jack Lloyd
4* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/mode_pad.h>
10
11#include <botan/exceptn.h>
12#include <botan/internal/ct_utils.h>
13
14namespace Botan {
15
16/**
17* Get a block cipher padding method by name
18*/
19std::unique_ptr<BlockCipherModePaddingMethod> BlockCipherModePaddingMethod::create(std::string_view algo_spec) {
20 if(algo_spec == "NoPadding") {
21 return std::make_unique<Null_Padding>();
22 }
23
24 if(algo_spec == "PKCS7") {
25 return std::make_unique<PKCS7_Padding>();
26 }
27
28 if(algo_spec == "OneAndZeros") {
29 return std::make_unique<OneAndZeros_Padding>();
30 }
31
32 if(algo_spec == "X9.23") {
33 return std::make_unique<ANSI_X923_Padding>();
34 }
35
36 if(algo_spec == "ESP") {
37 return std::make_unique<ESP_Padding>();
38 }
39
40 return nullptr;
41}
42
43/*
44* Pad with PKCS #7 Method
45*/
46void PKCS7_Padding::add_padding(secure_vector<uint8_t>& buffer, size_t last_byte_pos, size_t BS) const {
47 /*
48 Padding format is
49 01
50 0202
51 030303
52 ...
53 */
54 BOTAN_DEBUG_ASSERT(last_byte_pos < BS);
55
56 const uint8_t padding_len = static_cast<uint8_t>(BS - last_byte_pos);
57
58 buffer.resize(buffer.size() + padding_len);
59
60 CT::poison(&last_byte_pos, 1);
61 CT::poison(buffer.data(), buffer.size());
62
63 BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0);
64 BOTAN_DEBUG_ASSERT(buffer.size() >= BS);
65
66 const size_t start_of_last_block = buffer.size() - BS;
67 const size_t end_of_last_block = buffer.size();
68 const size_t start_of_padding = buffer.size() - padding_len;
69
70 for(size_t i = start_of_last_block; i != end_of_last_block; ++i) {
71 auto needs_padding = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gte(i, start_of_padding));
72 buffer[i] = needs_padding.select(padding_len, buffer[i]);
73 }
74
75 CT::unpoison(buffer.data(), buffer.size());
76 CT::unpoison(last_byte_pos);
77}
78
79/*
80* Unpad with PKCS #7 Method
81*/
82size_t PKCS7_Padding::unpad(const uint8_t input[], size_t input_length) const {
83 if(!valid_blocksize(input_length)) {
84 return input_length;
85 }
86
87 CT::poison(input, input_length);
88
89 const uint8_t last_byte = input[input_length - 1];
90
91 /*
92 The input should == the block size so if the last byte exceeds
93 that then the padding is certainly invalid
94 */
95 auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
96
97 const size_t pad_pos = input_length - last_byte;
98
99 for(size_t i = 0; i != input_length - 1; ++i) {
100 // Does this byte equal the expected pad byte?
101 const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
102
103 // Ignore values that are not part of the padding
104 const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
105 bad_input |= in_range & (~pad_eq);
106 }
107
108 CT::unpoison(input, input_length);
109
110 return bad_input.select_and_unpoison(input_length, pad_pos);
111}
112
113/*
114* Pad with ANSI X9.23 Method
115*/
116void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer, size_t last_byte_pos, size_t BS) const {
117 /*
118 Padding format is
119 01
120 0002
121 000003
122 ...
123 */
124 BOTAN_DEBUG_ASSERT(last_byte_pos < BS);
125
126 const uint8_t padding_len = static_cast<uint8_t>(BS - last_byte_pos);
127
128 buffer.resize(buffer.size() + padding_len);
129
130 CT::poison(&last_byte_pos, 1);
131 CT::poison(buffer.data(), buffer.size());
132
133 BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0);
134 BOTAN_DEBUG_ASSERT(buffer.size() >= BS);
135
136 const size_t start_of_last_block = buffer.size() - BS;
137 const size_t end_of_zero_padding = buffer.size() - 1;
138 const size_t start_of_padding = buffer.size() - padding_len;
139
140 for(size_t i = start_of_last_block; i != end_of_zero_padding; ++i) {
141 auto needs_padding = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gte(i, start_of_padding));
142 buffer[i] = needs_padding.select(0, buffer[i]);
143 }
144
145 buffer[buffer.size() - 1] = padding_len;
146 CT::unpoison(buffer.data(), buffer.size());
147 CT::unpoison(last_byte_pos);
148}
149
150/*
151* Unpad with ANSI X9.23 Method
152*/
153size_t ANSI_X923_Padding::unpad(const uint8_t input[], size_t input_length) const {
154 if(!valid_blocksize(input_length)) {
155 return input_length;
156 }
157
158 CT::poison(input, input_length);
159
160 const size_t last_byte = input[input_length - 1];
161
162 auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
163
164 const size_t pad_pos = input_length - last_byte;
165
166 for(size_t i = 0; i != input_length - 1; ++i) {
167 // Ignore values that are not part of the padding
168 const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
169 const auto pad_is_nonzero = CT::Mask<size_t>::expand(input[i]);
170 bad_input |= pad_is_nonzero & in_range;
171 }
172
173 CT::unpoison(input, input_length);
174
175 return bad_input.select_and_unpoison(input_length, pad_pos);
176}
177
178/*
179* Pad with One and Zeros Method
180*/
181void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer, size_t last_byte_pos, size_t BS) const {
182 /*
183 Padding format is
184 80
185 8000
186 800000
187 ...
188 */
189
190 BOTAN_DEBUG_ASSERT(last_byte_pos < BS);
191
192 const uint8_t padding_len = static_cast<uint8_t>(BS - last_byte_pos);
193
194 buffer.resize(buffer.size() + padding_len);
195
196 CT::poison(&last_byte_pos, 1);
197 CT::poison(buffer.data(), buffer.size());
198
199 BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0);
200 BOTAN_DEBUG_ASSERT(buffer.size() >= BS);
201
202 const size_t start_of_last_block = buffer.size() - BS;
203 const size_t end_of_last_block = buffer.size();
204 const size_t start_of_padding = buffer.size() - padding_len;
205
206 for(size_t i = start_of_last_block; i != end_of_last_block; ++i) {
207 auto needs_80 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_equal(i, start_of_padding));
208 auto needs_00 = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gt(i, start_of_padding));
209 buffer[i] = needs_00.select(0x00, needs_80.select(0x80, buffer[i]));
210 }
211
212 CT::unpoison(buffer.data(), buffer.size());
213 CT::unpoison(last_byte_pos);
214}
215
216/*
217* Unpad with One and Zeros Method
218*/
219size_t OneAndZeros_Padding::unpad(const uint8_t input[], size_t input_length) const {
220 if(!valid_blocksize(input_length)) {
221 return input_length;
222 }
223
224 CT::poison(input, input_length);
225
226 auto bad_input = CT::Mask<uint8_t>::cleared();
227 auto seen_0x80 = CT::Mask<uint8_t>::cleared();
228
229 size_t pad_pos = input_length - 1;
230 size_t i = input_length;
231
232 while(i) {
233 const auto is_0x80 = CT::Mask<uint8_t>::is_equal(input[i - 1], 0x80);
234 const auto is_zero = CT::Mask<uint8_t>::is_zero(input[i - 1]);
235
236 seen_0x80 |= is_0x80;
237 pad_pos -= seen_0x80.if_not_set_return(1);
238 bad_input |= ~seen_0x80 & ~is_zero;
239 i--;
240 }
241 bad_input |= ~seen_0x80;
242
243 CT::unpoison(input, input_length);
244
245 return CT::Mask<size_t>::expand(bad_input).select_and_unpoison(input_length, pad_pos);
246}
247
248/*
249* Pad with ESP Padding Method
250*/
251void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer, size_t last_byte_pos, size_t BS) const {
252 /*
253 Padding format is
254 01
255 0102
256 010203
257 ...
258 */
259 BOTAN_DEBUG_ASSERT(last_byte_pos < BS);
260
261 const uint8_t padding_len = static_cast<uint8_t>(BS - last_byte_pos);
262
263 buffer.resize(buffer.size() + padding_len);
264
265 CT::poison(&last_byte_pos, 1);
266 CT::poison(buffer.data(), buffer.size());
267
268 BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0);
269 BOTAN_DEBUG_ASSERT(buffer.size() >= BS);
270
271 const size_t start_of_last_block = buffer.size() - BS;
272 const size_t end_of_last_block = buffer.size();
273 const size_t start_of_padding = buffer.size() - padding_len;
274
275 uint8_t pad_ctr = 0x01;
276
277 for(size_t i = start_of_last_block; i != end_of_last_block; ++i) {
278 auto needs_padding = CT::Mask<uint8_t>(CT::Mask<size_t>::is_gte(i, start_of_padding));
279 buffer[i] = needs_padding.select(pad_ctr, buffer[i]);
280 pad_ctr = needs_padding.select(pad_ctr + 1, pad_ctr);
281 }
282
283 CT::unpoison(buffer.data(), buffer.size());
284 CT::unpoison(last_byte_pos);
285}
286
287/*
288* Unpad with ESP Padding Method
289*/
290size_t ESP_Padding::unpad(const uint8_t input[], size_t input_length) const {
291 if(!valid_blocksize(input_length)) {
292 return input_length;
293 }
294
295 CT::poison(input, input_length);
296
297 const uint8_t input_length_8 = static_cast<uint8_t>(input_length);
298 const uint8_t last_byte = input[input_length - 1];
299
300 auto bad_input = CT::Mask<uint8_t>::is_zero(last_byte) | CT::Mask<uint8_t>::is_gt(last_byte, input_length_8);
301
302 const uint8_t pad_pos = input_length_8 - last_byte;
303 size_t i = input_length_8 - 1;
304 while(i) {
305 const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
306 const auto incrementing = CT::Mask<uint8_t>::is_equal(input[i - 1], input[i] - 1);
307
308 bad_input |= CT::Mask<uint8_t>(in_range) & ~incrementing;
309 --i;
310 }
311
312 CT::unpoison(input, input_length);
313 return bad_input.select_and_unpoison(input_length_8, pad_pos);
314}
315
316} // namespace Botan
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition mode_pad.cpp:116
size_t unpad(const uint8_t[], size_t) const override
Definition mode_pad.cpp:153
bool valid_blocksize(size_t bs) const override
Definition mode_pad.h:90
static std::unique_ptr< BlockCipherModePaddingMethod > create(std::string_view algo_spec)
Definition mode_pad.cpp:19
static constexpr Mask< T > is_gte(T x, T y)
Definition ct_utils.h:154
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:115
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:134
static constexpr Mask< T > is_gt(T x, T y)
Definition ct_utils.h:144
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:129
static constexpr Mask< T > cleared()
Definition ct_utils.h:110
bool valid_blocksize(size_t bs) const override
Definition mode_pad.h:118
size_t unpad(const uint8_t[], size_t) const override
Definition mode_pad.cpp:290
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition mode_pad.cpp:251
size_t unpad(const uint8_t[], size_t) const override
Definition mode_pad.cpp:219
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition mode_pad.cpp:181
bool valid_blocksize(size_t bs) const override
Definition mode_pad.h:104
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition mode_pad.cpp:46
bool valid_blocksize(size_t bs) const override
Definition mode_pad.h:76
size_t unpad(const uint8_t[], size_t) const override
Definition mode_pad.cpp:82
void poison(const T *p, size_t n)
Definition ct_utils.h:46
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:57
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61