base64/
decode.rs

1use crate::engine::{general_purpose::STANDARD, DecodeEstimate, Engine};
2#[cfg(any(feature = "alloc", test))]
3use alloc::vec::Vec;
4use core::fmt;
5#[cfg(any(feature = "std", test))]
6use std::error;
7
8/// Errors that can occur while decoding.
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub 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
32impl fmt::Display for DecodeError {
33    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))]
48impl error::Error for DecodeError {}
49
50/// Errors that can occur while decoding into a slice.
51#[derive(Clone, Debug, PartialEq, Eq)]
52pub enum DecodeSliceError {
53    /// A [DecodeError] occurred
54    DecodeError(DecodeError),
55    /// The provided slice is too small.
56    OutputSliceTooSmall,
57}
58
59impl fmt::Display for DecodeSliceError {
60    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))]
69impl error::Error for DecodeSliceError {
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
78impl From<DecodeError> for DecodeSliceError {
79    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))]
89pub 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))]
99pub 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")]
111pub 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")]
123pub 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/// ```
149pub 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)]
156mod 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]
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]
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]
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]
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]
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
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)]
346mod coverage_gaming {
347    use super::*;
348    use std::error::Error;
349
350    #[test]
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]
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]
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]
383    fn decoded_len_est() {
384        assert_eq!(3, decoded_len_estimate(4));
385    }
386}