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