/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 | | } |