Botan  2.9.0
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 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 block_size) const
44  {
45  const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos);
46 
47  for(size_t i = 0; i != pad_value; ++i)
48  buffer.push_back(pad_value);
49  }
50 
51 /*
52 * Unpad with PKCS #7 Method
53 */
54 size_t PKCS7_Padding::unpad(const uint8_t input[], size_t input_length) const
55  {
56  if(!valid_blocksize(input_length))
57  return input_length;
58 
59  CT::poison(input, input_length);
60 
61  const uint8_t last_byte = input[input_length-1];
62 
63  /*
64  The input should == the block size so if the last byte exceeds
65  that then the padding is certainly invalid
66  */
67  auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
68 
69  const size_t pad_pos = input_length - last_byte;
70 
71  for(size_t i = 0; i != input_length - 1; ++i)
72  {
73  // Does this byte equal the expected pad byte?
74  const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
75 
76  // Ignore values that are not part of the padding
77  const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
78  bad_input |= in_range & (~pad_eq);
79  }
80 
81  CT::unpoison(input, input_length);
82 
83  return bad_input.select_and_unpoison(input_length, pad_pos);
84  }
85 
86 /*
87 * Pad with ANSI X9.23 Method
88 */
90  size_t last_byte_pos,
91  size_t block_size) const
92  {
93  const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos);
94 
95  for(size_t i = last_byte_pos; i < block_size-1; ++i)
96  {
97  buffer.push_back(0);
98  }
99  buffer.push_back(pad_value);
100  }
101 
102 /*
103 * Unpad with ANSI X9.23 Method
104 */
105 size_t ANSI_X923_Padding::unpad(const uint8_t input[], size_t input_length) const
106  {
107  if(!valid_blocksize(input_length))
108  return input_length;
109 
110  CT::poison(input, input_length);
111 
112  const size_t last_byte = input[input_length-1];
113 
114  auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
115 
116  const size_t pad_pos = input_length - last_byte;
117 
118  for(size_t i = 0; i != input_length - 1; ++i)
119  {
120  // Ignore values that are not part of the padding
121  const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
122  const auto pad_is_nonzero = CT::Mask<size_t>::expand(input[i]);
123  bad_input |= pad_is_nonzero & in_range;
124  }
125 
126  CT::unpoison(input, input_length);
127 
128  return bad_input.select_and_unpoison(input_length, pad_pos);
129  }
130 
131 /*
132 * Pad with One and Zeros Method
133 */
135  size_t last_byte_pos,
136  size_t block_size) const
137  {
138  buffer.push_back(0x80);
139 
140  for(size_t i = last_byte_pos + 1; i % block_size; ++i)
141  buffer.push_back(0x00);
142  }
143 
144 /*
145 * Unpad with One and Zeros Method
146 */
147 size_t OneAndZeros_Padding::unpad(const uint8_t input[], size_t input_length) const
148  {
149  if(!valid_blocksize(input_length))
150  return input_length;
151 
152  CT::poison(input, input_length);
153 
154  auto bad_input = CT::Mask<uint8_t>::cleared();
155  auto seen_0x80 = CT::Mask<uint8_t>::cleared();
156 
157  size_t pad_pos = input_length - 1;
158  size_t i = input_length;
159 
160  while(i)
161  {
162  const auto is_0x80 = CT::Mask<uint8_t>::is_equal(input[i-1], 0x80);
163  const auto is_zero = CT::Mask<uint8_t>::is_zero(input[i-1]);
164 
165  seen_0x80 |= is_0x80;
166  pad_pos -= seen_0x80.if_not_set_return(1);
167  bad_input |= ~seen_0x80 & ~is_zero;
168  i--;
169  }
170  bad_input |= ~seen_0x80;
171 
172  CT::unpoison(input, input_length);
173 
174  return CT::Mask<size_t>::expand(bad_input).select_and_unpoison(input_length, pad_pos);
175  }
176 
177 /*
178 * Pad with ESP Padding Method
179 */
181  size_t last_byte_pos,
182  size_t block_size) const
183  {
184  uint8_t pad_value = 0x01;
185 
186  for(size_t i = last_byte_pos; i < block_size; ++i)
187  {
188  buffer.push_back(pad_value++);
189  }
190  }
191 
192 /*
193 * Unpad with ESP Padding Method
194 */
195 size_t ESP_Padding::unpad(const uint8_t input[], size_t input_length) const
196  {
197  if(!valid_blocksize(input_length))
198  return input_length;
199 
200  CT::poison(input, input_length);
201 
202  const uint8_t input_length_8 = static_cast<uint8_t>(input_length);
203  const uint8_t last_byte = input[input_length-1];
204 
205  auto bad_input = CT::Mask<uint8_t>::is_zero(last_byte) |
206  CT::Mask<uint8_t>::is_gt(last_byte, input_length_8);
207 
208  const uint8_t pad_pos = input_length_8 - last_byte;
209  size_t i = input_length_8 - 1;
210  while(i)
211  {
212  const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
213  const auto incrementing = CT::Mask<uint8_t>::is_equal(input[i-1], input[i]-1);
214 
215  bad_input |= CT::Mask<uint8_t>(in_range) & ~incrementing;
216  --i;
217  }
218 
219  CT::unpoison(input, input_length);
220  return bad_input.select_and_unpoison(input_length_8, pad_pos);
221  }
222 
223 
224 }
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:195
static Mask< T > cleared()
Definition: ct_utils.h:115
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:127
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:93
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:54
void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const override
Definition: mode_pad.cpp:89
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:180
static Mask< T > expand(T v)
Definition: ct_utils.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:134
size_t unpad(const uint8_t[], size_t) const override
Definition: mode_pad.cpp:105
bool valid_blocksize(size_t bs) const override
Definition: mode_pad.h:76
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:110
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:147
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
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