1 | use crate::engine::{general_purpose::STANDARD, DecodeEstimate, Engine}; |
2 | #[cfg (any(feature = "alloc" , test))] |
3 | use alloc::vec::Vec; |
4 | use core::fmt; |
5 | #[cfg (any(feature = "std" , test))] |
6 | use std::error; |
7 | |
8 | /// Errors that can occur while decoding. |
9 | #[derive (Clone, Debug, PartialEq, Eq)] |
10 | pub enum DecodeError { |
11 | /// An invalid byte was found in the input. The offset and offending byte are provided. |
12 | /// Padding characters (`=`) interspersed in the encoded form will be treated as invalid bytes. |
13 | InvalidByte(usize, u8), |
14 | /// The length of the input is invalid. |
15 | /// A typical cause of this is stray trailing whitespace or other separator bytes. |
16 | /// In the case where excess trailing bytes have produced an invalid length *and* the last byte |
17 | /// is also an invalid base64 symbol (as would be the case for whitespace, etc), `InvalidByte` |
18 | /// will be emitted instead of `InvalidLength` to make the issue easier to debug. |
19 | InvalidLength, |
20 | /// The last non-padding input symbol's encoded 6 bits have nonzero bits that will be discarded. |
21 | /// This is indicative of corrupted or truncated Base64. |
22 | /// Unlike `InvalidByte`, which reports symbols that aren't in the alphabet, this error is for |
23 | /// symbols that are in the alphabet but represent nonsensical encodings. |
24 | InvalidLastSymbol(usize, u8), |
25 | /// The nature of the padding was not as configured: absent or incorrect when it must be |
26 | /// canonical, or present when it must be absent, etc. |
27 | InvalidPadding, |
28 | } |
29 | |
30 | impl fmt::Display for DecodeError { |
31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
32 | match *self { |
33 | Self::InvalidByte(index: usize, byte: u8) => write!(f, "Invalid byte {}, offset {}." , byte, index), |
34 | Self::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder." ), |
35 | Self::InvalidLastSymbol(index: usize, byte: u8) => { |
36 | write!(f, "Invalid last symbol {}, offset {}." , byte, index) |
37 | } |
38 | Self::InvalidPadding => write!(f, "Invalid padding" ), |
39 | } |
40 | } |
41 | } |
42 | |
43 | #[cfg (any(feature = "std" , test))] |
44 | impl error::Error for DecodeError {} |
45 | |
46 | /// Errors that can occur while decoding into a slice. |
47 | #[derive (Clone, Debug, PartialEq, Eq)] |
48 | pub enum DecodeSliceError { |
49 | /// A [DecodeError] occurred |
50 | DecodeError(DecodeError), |
51 | /// The provided slice _may_ be too small. |
52 | /// |
53 | /// The check is conservative (assumes the last triplet of output bytes will all be needed). |
54 | OutputSliceTooSmall, |
55 | } |
56 | |
57 | impl fmt::Display for DecodeSliceError { |
58 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
59 | match self { |
60 | Self::DecodeError(e: &DecodeError) => write!(f, "DecodeError: {}" , e), |
61 | Self::OutputSliceTooSmall => write!(f, "Output slice too small" ), |
62 | } |
63 | } |
64 | } |
65 | |
66 | #[cfg (any(feature = "std" , test))] |
67 | impl error::Error for DecodeSliceError { |
68 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
69 | match self { |
70 | DecodeSliceError::DecodeError(e: &DecodeError) => Some(e), |
71 | DecodeSliceError::OutputSliceTooSmall => None, |
72 | } |
73 | } |
74 | } |
75 | |
76 | impl From<DecodeError> for DecodeSliceError { |
77 | fn from(e: DecodeError) -> Self { |
78 | DecodeSliceError::DecodeError(e) |
79 | } |
80 | } |
81 | |
82 | /// Decode base64 using the [`STANDARD` engine](STANDARD). |
83 | /// |
84 | /// See [Engine::decode]. |
85 | #[deprecated (since = "0.21.0" , note = "Use Engine::decode" )] |
86 | #[cfg (any(feature = "alloc" , test))] |
87 | pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> { |
88 | STANDARD.decode(input) |
89 | } |
90 | |
91 | /// Decode from string reference as octets using the specified [Engine]. |
92 | /// |
93 | /// See [Engine::decode]. |
94 | ///Returns a `Result` containing a `Vec<u8>`. |
95 | #[deprecated (since = "0.21.0" , note = "Use Engine::decode" )] |
96 | #[cfg (any(feature = "alloc" , test))] |
97 | pub fn decode_engine<E: Engine, T: AsRef<[u8]>>( |
98 | input: T, |
99 | engine: &E, |
100 | ) -> Result<Vec<u8>, DecodeError> { |
101 | engine.decode(input) |
102 | } |
103 | |
104 | /// Decode from string reference as octets. |
105 | /// |
106 | /// See [Engine::decode_vec]. |
107 | #[cfg (any(feature = "alloc" , test))] |
108 | #[deprecated (since = "0.21.0" , note = "Use Engine::decode_vec" )] |
109 | pub fn decode_engine_vec<E: Engine, T: AsRef<[u8]>>( |
110 | input: T, |
111 | buffer: &mut Vec<u8>, |
112 | engine: &E, |
113 | ) -> Result<(), DecodeError> { |
114 | engine.decode_vec(input, buffer) |
115 | } |
116 | |
117 | /// Decode the input into the provided output slice. |
118 | /// |
119 | /// See [Engine::decode_slice]. |
120 | #[deprecated (since = "0.21.0" , note = "Use Engine::decode_slice" )] |
121 | pub fn decode_engine_slice<E: Engine, T: AsRef<[u8]>>( |
122 | input: T, |
123 | output: &mut [u8], |
124 | engine: &E, |
125 | ) -> Result<usize, DecodeSliceError> { |
126 | engine.decode_slice(input, output) |
127 | } |
128 | |
129 | /// Returns a conservative estimate of the decoded size of `encoded_len` base64 symbols (rounded up |
130 | /// to the next group of 3 decoded bytes). |
131 | /// |
132 | /// The resulting length will be a safe choice for the size of a decode buffer, but may have up to |
133 | /// 2 trailing bytes that won't end up being needed. |
134 | /// |
135 | /// # Examples |
136 | /// |
137 | /// ``` |
138 | /// use base64::decoded_len_estimate; |
139 | /// |
140 | /// assert_eq!(3, decoded_len_estimate(1)); |
141 | /// assert_eq!(3, decoded_len_estimate(2)); |
142 | /// assert_eq!(3, decoded_len_estimate(3)); |
143 | /// assert_eq!(3, decoded_len_estimate(4)); |
144 | /// // start of the next quad of encoded symbols |
145 | /// assert_eq!(6, decoded_len_estimate(5)); |
146 | /// ``` |
147 | pub fn decoded_len_estimate(encoded_len: usize) -> usize { |
148 | STANDARD |
149 | .internal_decoded_len_estimate(input_len:encoded_len) |
150 | .decoded_len_estimate() |
151 | } |
152 | |
153 | #[cfg (test)] |
154 | mod tests { |
155 | use super::*; |
156 | use crate::{ |
157 | alphabet, |
158 | engine::{general_purpose, Config, GeneralPurpose}, |
159 | tests::{assert_encode_sanity, random_engine}, |
160 | }; |
161 | use rand::{ |
162 | distributions::{Distribution, Uniform}, |
163 | Rng, SeedableRng, |
164 | }; |
165 | |
166 | #[test ] |
167 | fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() { |
168 | let mut orig_data = Vec::new(); |
169 | let mut encoded_data = String::new(); |
170 | let mut decoded_with_prefix = Vec::new(); |
171 | let mut decoded_without_prefix = Vec::new(); |
172 | let mut prefix = Vec::new(); |
173 | |
174 | let prefix_len_range = Uniform::new(0, 1000); |
175 | let input_len_range = Uniform::new(0, 1000); |
176 | |
177 | let mut rng = rand::rngs::SmallRng::from_entropy(); |
178 | |
179 | for _ in 0..10_000 { |
180 | orig_data.clear(); |
181 | encoded_data.clear(); |
182 | decoded_with_prefix.clear(); |
183 | decoded_without_prefix.clear(); |
184 | prefix.clear(); |
185 | |
186 | let input_len = input_len_range.sample(&mut rng); |
187 | |
188 | for _ in 0..input_len { |
189 | orig_data.push(rng.gen()); |
190 | } |
191 | |
192 | let engine = random_engine(&mut rng); |
193 | engine.encode_string(&orig_data, &mut encoded_data); |
194 | assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); |
195 | |
196 | let prefix_len = prefix_len_range.sample(&mut rng); |
197 | |
198 | // fill the buf with a prefix |
199 | for _ in 0..prefix_len { |
200 | prefix.push(rng.gen()); |
201 | } |
202 | |
203 | decoded_with_prefix.resize(prefix_len, 0); |
204 | decoded_with_prefix.copy_from_slice(&prefix); |
205 | |
206 | // decode into the non-empty buf |
207 | engine |
208 | .decode_vec(&encoded_data, &mut decoded_with_prefix) |
209 | .unwrap(); |
210 | // also decode into the empty buf |
211 | engine |
212 | .decode_vec(&encoded_data, &mut decoded_without_prefix) |
213 | .unwrap(); |
214 | |
215 | assert_eq!( |
216 | prefix_len + decoded_without_prefix.len(), |
217 | decoded_with_prefix.len() |
218 | ); |
219 | assert_eq!(orig_data, decoded_without_prefix); |
220 | |
221 | // append plain decode onto prefix |
222 | prefix.append(&mut decoded_without_prefix); |
223 | |
224 | assert_eq!(prefix, decoded_with_prefix); |
225 | } |
226 | } |
227 | |
228 | #[test ] |
229 | fn decode_slice_doesnt_clobber_existing_prefix_or_suffix() { |
230 | do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| { |
231 | e.decode_slice(input, output).unwrap() |
232 | }) |
233 | } |
234 | |
235 | #[test ] |
236 | fn decode_slice_unchecked_doesnt_clobber_existing_prefix_or_suffix() { |
237 | do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| { |
238 | e.decode_slice_unchecked(input, output).unwrap() |
239 | }) |
240 | } |
241 | |
242 | #[test ] |
243 | fn decode_engine_estimation_works_for_various_lengths() { |
244 | let engine = GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD); |
245 | for num_prefix_quads in 0..100 { |
246 | for suffix in &["AA" , "AAA" , "AAAA" ] { |
247 | let mut prefix = "AAAA" .repeat(num_prefix_quads); |
248 | prefix.push_str(suffix); |
249 | // make sure no overflow (and thus a panic) occurs |
250 | let res = engine.decode(prefix); |
251 | assert!(res.is_ok()); |
252 | } |
253 | } |
254 | } |
255 | |
256 | #[test ] |
257 | fn decode_slice_output_length_errors() { |
258 | for num_quads in 1..100 { |
259 | let input = "AAAA" .repeat(num_quads); |
260 | let mut vec = vec![0; (num_quads - 1) * 3]; |
261 | assert_eq!( |
262 | DecodeSliceError::OutputSliceTooSmall, |
263 | STANDARD.decode_slice(&input, &mut vec).unwrap_err() |
264 | ); |
265 | vec.push(0); |
266 | assert_eq!( |
267 | DecodeSliceError::OutputSliceTooSmall, |
268 | STANDARD.decode_slice(&input, &mut vec).unwrap_err() |
269 | ); |
270 | vec.push(0); |
271 | assert_eq!( |
272 | DecodeSliceError::OutputSliceTooSmall, |
273 | STANDARD.decode_slice(&input, &mut vec).unwrap_err() |
274 | ); |
275 | vec.push(0); |
276 | // now it works |
277 | assert_eq!( |
278 | num_quads * 3, |
279 | STANDARD.decode_slice(&input, &mut vec).unwrap() |
280 | ); |
281 | } |
282 | } |
283 | |
284 | fn do_decode_slice_doesnt_clobber_existing_prefix_or_suffix< |
285 | F: Fn(&GeneralPurpose, &[u8], &mut [u8]) -> usize, |
286 | >( |
287 | call_decode: F, |
288 | ) { |
289 | let mut orig_data = Vec::new(); |
290 | let mut encoded_data = String::new(); |
291 | let mut decode_buf = Vec::new(); |
292 | let mut decode_buf_copy: Vec<u8> = Vec::new(); |
293 | |
294 | let input_len_range = Uniform::new(0, 1000); |
295 | |
296 | let mut rng = rand::rngs::SmallRng::from_entropy(); |
297 | |
298 | for _ in 0..10_000 { |
299 | orig_data.clear(); |
300 | encoded_data.clear(); |
301 | decode_buf.clear(); |
302 | decode_buf_copy.clear(); |
303 | |
304 | let input_len = input_len_range.sample(&mut rng); |
305 | |
306 | for _ in 0..input_len { |
307 | orig_data.push(rng.gen()); |
308 | } |
309 | |
310 | let engine = random_engine(&mut rng); |
311 | engine.encode_string(&orig_data, &mut encoded_data); |
312 | assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); |
313 | |
314 | // fill the buffer with random garbage, long enough to have some room before and after |
315 | for _ in 0..5000 { |
316 | decode_buf.push(rng.gen()); |
317 | } |
318 | |
319 | // keep a copy for later comparison |
320 | decode_buf_copy.extend(decode_buf.iter()); |
321 | |
322 | let offset = 1000; |
323 | |
324 | // decode into the non-empty buf |
325 | let decode_bytes_written = |
326 | call_decode(&engine, encoded_data.as_bytes(), &mut decode_buf[offset..]); |
327 | |
328 | assert_eq!(orig_data.len(), decode_bytes_written); |
329 | assert_eq!( |
330 | orig_data, |
331 | &decode_buf[offset..(offset + decode_bytes_written)] |
332 | ); |
333 | assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]); |
334 | assert_eq!( |
335 | &decode_buf_copy[offset + decode_bytes_written..], |
336 | &decode_buf[offset + decode_bytes_written..] |
337 | ); |
338 | } |
339 | } |
340 | } |
341 | |