Coverage Report

Created: 2019-12-03 15:21

/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
141
   {
56
141
   if(!valid_blocksize(input_length))
57
0
      return input_length;
58
141
59
141
   CT::poison(input, input_length);
60
141
61
141
   const uint8_t last_byte = input[input_length-1];
62
141
63
141
   /*
64
141
   The input should == the block size so if the last byte exceeds
65
141
   that then the padding is certainly invalid
66
141
   */
67
141
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
68
141
69
141
   const size_t pad_pos = input_length - last_byte;
70
141
71
6.42k
   for(size_t i = 0; i != input_length - 1; ++i)
72
6.28k
      {
73
6.28k
      // Does this byte equal the expected pad byte?
74
6.28k
      const auto pad_eq = CT::Mask<size_t>::is_equal(input[i], last_byte);
75
6.28k
76
6.28k
      // Ignore values that are not part of the padding
77
6.28k
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
78
6.28k
      bad_input |= in_range & (~pad_eq);
79
6.28k
      }
80
141
81
141
   CT::unpoison(input, input_length);
82
141
83
141
   return bad_input.select_and_unpoison(input_length, pad_pos);
84
141
   }
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
141
   {
107
141
   if(!valid_blocksize(input_length))
108
0
      return input_length;
109
141
110
141
   CT::poison(input, input_length);
111
141
112
141
   const size_t last_byte = input[input_length-1];
113
141
114
141
   auto bad_input = CT::Mask<size_t>::is_gt(last_byte, input_length);
115
141
116
141
   const size_t pad_pos = input_length - last_byte;
117
141
118
6.42k
   for(size_t i = 0; i != input_length - 1; ++i)
119
6.28k
      {
120
6.28k
      // Ignore values that are not part of the padding
121
6.28k
      const auto in_range = CT::Mask<size_t>::is_gte(i, pad_pos);
122
6.28k
      const auto pad_is_nonzero = CT::Mask<size_t>::expand(input[i]);
123
6.28k
      bad_input |= pad_is_nonzero & in_range;
124
6.28k
      }
125
141
126
141
   CT::unpoison(input, input_length);
127
141
128
141
   return bad_input.select_and_unpoison(input_length, pad_pos);
129
141
   }
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
198
   {
149
198
   if(!valid_blocksize(input_length))
150
0
      return input_length;
151
198
152
198
   CT::poison(input, input_length);
153
198
154
198
   auto bad_input = CT::Mask<uint8_t>::cleared();
155
198
   auto seen_0x80 = CT::Mask<uint8_t>::cleared();
156
198
157
198
   size_t pad_pos = input_length - 1;
158
198
   size_t i = input_length;
159
198
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
198
   bad_input |= ~seen_0x80;
171
198
172
198
   CT::unpoison(input, input_length);
173
198
174
198
   return CT::Mask<size_t>::expand(bad_input).select_and_unpoison(input_length, pad_pos);
175
198
   }
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
141
   {
197
141
   if(!valid_blocksize(input_length))
198
0
      return input_length;
199
141
200
141
   CT::poison(input, input_length);
201
141
202
141
   const uint8_t input_length_8 = static_cast<uint8_t>(input_length);
203
141
   const uint8_t last_byte = input[input_length-1];
204
141
205
141
   auto bad_input = CT::Mask<uint8_t>::is_zero(last_byte) |
206
141
      CT::Mask<uint8_t>::is_gt(last_byte, input_length_8);
207
141
208
141
   const uint8_t pad_pos = input_length_8 - last_byte;
209
141
   size_t i = input_length_8 - 1;
210
6.42k
   while(i)
211
6.28k
      {
212
6.28k
      const auto in_range = CT::Mask<size_t>::is_gt(i, pad_pos);
213
6.28k
      const auto incrementing = CT::Mask<uint8_t>::is_equal(input[i-1], input[i]-1);
214
6.28k
215
6.28k
      bad_input |= CT::Mask<uint8_t>(in_range) & ~incrementing;
216
6.28k
      --i;
217
6.28k
      }
218
141
219
141
   CT::unpoison(input, input_length);
220
141
   return bad_input.select_and_unpoison(input_length_8, pad_pos);
221
141
   }
222
223
224
}