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