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