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