Coverage Report

Created: 2020-02-14 15:38

/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 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
0
   {
20
0
   if(algo_spec == "NoPadding")
21
0
      return new Null_Padding;
22
0
23
0
   if(algo_spec == "PKCS7")
24
0
      return new PKCS7_Padding;
25
0
26
0
   if(algo_spec == "OneAndZeros")
27
0
      return new OneAndZeros_Padding;
28
0
29
0
   if(algo_spec == "X9.23")
30
0
      return new ANSI_X923_Padding;
31
0
32
0
   if(algo_spec == "ESP")
33
0
      return new ESP_Padding;
34
0
35
0
   return nullptr;
36
0
   }
37
38
/*
39
* Pad with PKCS #7 Method
40
*/
41
void PKCS7_Padding::add_padding(secure_vector<uint8_t>& buffer,
42
                                size_t last_byte_pos,
43
                                size_t block_size) const
44
0
   {
45
0
   const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos);
46
0
47
0
   for(size_t i = 0; i != pad_value; ++i)
48
0
      buffer.push_back(pad_value);
49
0
   }
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
139
   {
56
139
   if(!valid_blocksize(input_length))
57
0
      return input_length;
58
139
59
139
   CT::poison(input, input_length);
60
139
61
139
   const uint8_t last_byte = input[input_length-1];
62
139
63
139
   /*
64
139
   The input should == the block size so if the last byte exceeds
65
139
   that then the padding is certainly invalid
66
139
   */
67
139
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
68
139
69
139
   const size_t pad_pos = input_length - last_byte;
70
139
71
6.40k
   for(size_t i = 0; i != input_length - 1; ++i)
72
6.26k
      {
73
6.26k
      // Does this byte equal the expected pad byte?
74
6.26k
      const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
75
6.26k
76
6.26k
      // Ignore values that are not part of the padding
77
6.26k
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
78
6.26k
      bad_input |= in_range & (~pad_eq);
79
6.26k
      }
80
139
81
139
   CT::unpoison(input, input_length);
82
139
83
139
   return bad_input.select_and_unpoison(input_length, pad_pos);
84
139
   }
85
86
/*
87
* Pad with ANSI X9.23 Method
88
*/
89
void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer,
90
                                    size_t last_byte_pos,
91
                                    size_t block_size) const
92
0
   {
93
0
   const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos);
94
0
95
0
   for(size_t i = last_byte_pos; i < block_size-1; ++i)
96
0
      {
97
0
      buffer.push_back(0);
98
0
      }
99
0
   buffer.push_back(pad_value);
100
0
   }
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
139
   {
107
139
   if(!valid_blocksize(input_length))
108
0
      return input_length;
109
139
110
139
   CT::poison(input, input_length);
111
139
112
139
   const size_t last_byte = input[input_length-1];
113
139
114
139
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
115
139
116
139
   const size_t pad_pos = input_length - last_byte;
117
139
118
6.40k
   for(size_t i = 0; i != input_length - 1; ++i)
119
6.26k
      {
120
6.26k
      // Ignore values that are not part of the padding
121
6.26k
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
122
6.26k
      const auto pad_is_nonzero = CT::Mask<size_t>::expand(input[i]);
123
6.26k
      bad_input |= pad_is_nonzero & in_range;
124
6.26k
      }
125
139
126
139
   CT::unpoison(input, input_length);
127
139
128
139
   return bad_input.select_and_unpoison(input_length, pad_pos);
129
139
   }
130
131
/*
132
* Pad with One and Zeros Method
133
*/
134
void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer,
135
                                      size_t last_byte_pos,
136
                                      size_t block_size) const
137
0
   {
138
0
   buffer.push_back(0x80);
139
0
140
0
   for(size_t i = last_byte_pos + 1; i % block_size; ++i)
141
0
      buffer.push_back(0x00);
142
0
   }
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
196
   {
149
196
   if(!valid_blocksize(input_length))
150
0
      return input_length;
151
196
152
196
   CT::poison(input, input_length);
153
196
154
196
   auto bad_input = CT::Mask<uint8_t>::cleared();
155
196
   auto seen_0x80 = CT::Mask<uint8_t>::cleared();
156
196
157
196
   size_t pad_pos = input_length - 1;
158
196
   size_t i = input_length;
159
196
160
193k
   while(i)
161
193k
      {
162
193k
      const auto is_0x80 = CT::Mask<uint8_t>::is_equal(input[i-1], 0x80);
163
193k
      const auto is_zero = CT::Mask<uint8_t>::is_zero(input[i-1]);
164
193k
165
193k
      seen_0x80 |= is_0x80;
166
193k
      pad_pos -= seen_0x80.if_not_set_return(1);
167
193k
      bad_input |= ~seen_0x80 & ~is_zero;
168
193k
      i--;
169
193k
      }
170
196
   bad_input |= ~seen_0x80;
171
196
172
196
   CT::unpoison(input, input_length);
173
196
174
196
   return CT::Mask<size_t>::expand(bad_input).select_and_unpoison(input_length, pad_pos);
175
196
   }
176
177
/*
178
* Pad with ESP Padding Method
179
*/
180
void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer,
181
                              size_t last_byte_pos,
182
                              size_t block_size) const
183
0
   {
184
0
   uint8_t pad_value = 0x01;
185
0
186
0
   for(size_t i = last_byte_pos; i < block_size; ++i)
187
0
      {
188
0
      buffer.push_back(pad_value++);
189
0
      }
190
0
   }
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
139
   {
197
139
   if(!valid_blocksize(input_length))
198
0
      return input_length;
199
139
200
139
   CT::poison(input, input_length);
201
139
202
139
   const uint8_t input_length_8 = static_cast<uint8_t>(input_length);
203
139
   const uint8_t last_byte = input[input_length-1];
204
139
205
139
   auto bad_input = CT::Mask<uint8_t>::is_zero(last_byte) |
206
139
      CT::Mask<uint8_t>::is_gt(last_byte, input_length_8);
207
139
208
139
   const uint8_t pad_pos = input_length_8 - last_byte;
209
139
   size_t i = input_length_8 - 1;
210
6.40k
   while(i)
211
6.26k
      {
212
6.26k
      const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
213
6.26k
      const auto incrementing = CT::Mask<uint8_t>::is_equal(input[i-1], input[i]-1);
214
6.26k
215
6.26k
      bad_input |= CT::Mask<uint8_t>(in_range) & ~incrementing;
216
6.26k
      --i;
217
6.26k
      }
218
139
219
139
   CT::unpoison(input, input_length);
220
139
   return bad_input.select_and_unpoison(input_length_8, pad_pos);
221
139
   }
222
223
224
}