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