Botan  2.19.1
Crypto and TLS for C++11
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 
13 namespace Botan {
14 
15 /**
16 * Get a block cipher padding method by name
17 */
18 BlockCipherModePaddingMethod* 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 */
81 size_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 */
157 size_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 */
228 size_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 */
304 size_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 }
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:304
static Mask< T > cleared()
Definition: ct_utils.h:115
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:129
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:95
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:81
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition: mode_pad.cpp:116
static Mask< T > is_gte(T x, T y)
Definition: ct_utils.h:181
void poison(const T *p, size_t n)
Definition: ct_utils.h:48
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition: mode_pad.cpp:261
T select(T x, T y) const
Definition: ct_utils.h:288
static Mask< T > expand(T v)
Definition: ct_utils.h:123
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
#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:186
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:78
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition: mode_pad.cpp:41
Definition: alg_id.cpp:13
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:112
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:59
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:228
static Mask< T > is_zero(T x)
Definition: ct_utils.h:141
static Mask< T > is_equal(T x, T y)
Definition: ct_utils.h:149
static Mask< T > is_gt(T x, T y)
Definition: ct_utils.h:165
BlockCipherModePaddingMethod * get_bc_pad(const std::string &algo_spec)
Definition: mode_pad.cpp:18