Coverage Report

Created: 2021-05-04 09:02

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