1#![cfg_attr(not(feature = "std"), no_std)]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4#![deny(clippy::all)]
5#![deny(clippy::pedantic)]
6#![allow(clippy::missing_errors_doc)]
7
8#[cfg(feature = "alloc")]
46extern crate alloc;
47
48#[cfg(feature = "stream")]
49pub mod stream {
50 use super::{Alphabet, DecodeError, EncodeError, Engine};
80 use std::collections::VecDeque;
81 use std::io::{self, Read, Write};
82
83 pub struct Encoder<W, A, const PAD: bool>
85 where
86 A: Alphabet,
87 {
88 inner: W,
89 engine: Engine<A, PAD>,
90 pending: [u8; 2],
91 pending_len: usize,
92 }
93
94 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
95 where
96 A: Alphabet,
97 {
98 #[must_use]
100 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
101 Self {
102 inner,
103 engine,
104 pending: [0; 2],
105 pending_len: 0,
106 }
107 }
108
109 #[must_use]
111 pub const fn get_ref(&self) -> &W {
112 &self.inner
113 }
114
115 pub fn get_mut(&mut self) -> &mut W {
117 &mut self.inner
118 }
119
120 #[must_use]
124 pub fn into_inner(self) -> W {
125 self.inner
126 }
127 }
128
129 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
130 where
131 W: Write,
132 A: Alphabet,
133 {
134 pub fn finish(mut self) -> io::Result<W> {
136 self.write_pending_final()?;
137 self.inner.flush()?;
138 Ok(self.inner)
139 }
140
141 fn write_pending_final(&mut self) -> io::Result<()> {
142 if self.pending_len == 0 {
143 return Ok(());
144 }
145
146 let mut encoded = [0u8; 4];
147 let written = self
148 .engine
149 .encode_slice(&self.pending[..self.pending_len], &mut encoded)
150 .map_err(encode_error_to_io)?;
151 self.inner.write_all(&encoded[..written])?;
152 self.pending_len = 0;
153 Ok(())
154 }
155 }
156
157 impl<W, A, const PAD: bool> Write for Encoder<W, A, PAD>
158 where
159 W: Write,
160 A: Alphabet,
161 {
162 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
163 if input.is_empty() {
164 return Ok(0);
165 }
166
167 let mut consumed = 0;
168 if self.pending_len > 0 {
169 let needed = 3 - self.pending_len;
170 if input.len() < needed {
171 self.pending[self.pending_len..self.pending_len + input.len()]
172 .copy_from_slice(input);
173 self.pending_len += input.len();
174 return Ok(input.len());
175 }
176
177 let mut chunk = [0u8; 3];
178 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
179 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
180
181 let mut encoded = [0u8; 4];
182 let written = self
183 .engine
184 .encode_slice(&chunk, &mut encoded)
185 .map_err(encode_error_to_io)?;
186 self.inner.write_all(&encoded[..written])?;
187 self.pending_len = 0;
188 consumed += needed;
189 }
190
191 let remaining = &input[consumed..];
192 let full_len = remaining.len() / 3 * 3;
193 let mut offset = 0;
194 let mut encoded = [0u8; 1024];
195 while offset < full_len {
196 let mut take = core::cmp::min(full_len - offset, 768);
197 take -= take % 3;
198 debug_assert!(take > 0);
199
200 let written = self
201 .engine
202 .encode_slice(&remaining[offset..offset + take], &mut encoded)
203 .map_err(encode_error_to_io)?;
204 self.inner.write_all(&encoded[..written])?;
205 offset += take;
206 }
207
208 let tail = &remaining[full_len..];
209 self.pending[..tail.len()].copy_from_slice(tail);
210 self.pending_len = tail.len();
211
212 Ok(input.len())
213 }
214
215 fn flush(&mut self) -> io::Result<()> {
216 self.inner.flush()
217 }
218 }
219
220 fn encode_error_to_io(err: EncodeError) -> io::Error {
221 io::Error::new(io::ErrorKind::InvalidInput, err)
222 }
223
224 pub struct Decoder<W, A, const PAD: bool>
226 where
227 A: Alphabet,
228 {
229 inner: W,
230 engine: Engine<A, PAD>,
231 pending: [u8; 4],
232 pending_len: usize,
233 finished: bool,
234 }
235
236 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
237 where
238 A: Alphabet,
239 {
240 #[must_use]
242 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
243 Self {
244 inner,
245 engine,
246 pending: [0; 4],
247 pending_len: 0,
248 finished: false,
249 }
250 }
251
252 #[must_use]
254 pub const fn get_ref(&self) -> &W {
255 &self.inner
256 }
257
258 pub fn get_mut(&mut self) -> &mut W {
260 &mut self.inner
261 }
262
263 #[must_use]
267 pub fn into_inner(self) -> W {
268 self.inner
269 }
270 }
271
272 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
273 where
274 W: Write,
275 A: Alphabet,
276 {
277 pub fn finish(mut self) -> io::Result<W> {
279 self.write_pending_final()?;
280 self.inner.flush()?;
281 Ok(self.inner)
282 }
283
284 fn write_pending_final(&mut self) -> io::Result<()> {
285 if self.pending_len == 0 {
286 return Ok(());
287 }
288
289 let mut decoded = [0u8; 3];
290 let written = self
291 .engine
292 .decode_slice(&self.pending[..self.pending_len], &mut decoded)
293 .map_err(decode_error_to_io)?;
294 self.inner.write_all(&decoded[..written])?;
295 self.pending_len = 0;
296 Ok(())
297 }
298
299 fn write_full_quad(&mut self, input: [u8; 4]) -> io::Result<()> {
300 let mut decoded = [0u8; 3];
301 let written = self
302 .engine
303 .decode_slice(&input, &mut decoded)
304 .map_err(decode_error_to_io)?;
305 self.inner.write_all(&decoded[..written])?;
306 if written < 3 {
307 self.finished = true;
308 }
309 Ok(())
310 }
311 }
312
313 impl<W, A, const PAD: bool> Write for Decoder<W, A, PAD>
314 where
315 W: Write,
316 A: Alphabet,
317 {
318 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
319 if input.is_empty() {
320 return Ok(0);
321 }
322 if self.finished {
323 return Err(trailing_input_after_padding_error());
324 }
325
326 let mut consumed = 0;
327 if self.pending_len > 0 {
328 let needed = 4 - self.pending_len;
329 if input.len() < needed {
330 self.pending[self.pending_len..self.pending_len + input.len()]
331 .copy_from_slice(input);
332 self.pending_len += input.len();
333 return Ok(input.len());
334 }
335
336 let mut quad = [0u8; 4];
337 quad[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
338 quad[self.pending_len..].copy_from_slice(&input[..needed]);
339 self.write_full_quad(quad)?;
340 self.pending_len = 0;
341 consumed += needed;
342 if self.finished && consumed < input.len() {
343 return Err(trailing_input_after_padding_error());
344 }
345 }
346
347 let remaining = &input[consumed..];
348 let full_len = remaining.len() / 4 * 4;
349 let mut offset = 0;
350 while offset < full_len {
351 let quad = [
352 remaining[offset],
353 remaining[offset + 1],
354 remaining[offset + 2],
355 remaining[offset + 3],
356 ];
357 self.write_full_quad(quad)?;
358 offset += 4;
359 if self.finished && offset < remaining.len() {
360 return Err(trailing_input_after_padding_error());
361 }
362 }
363
364 let tail = &remaining[full_len..];
365 self.pending[..tail.len()].copy_from_slice(tail);
366 self.pending_len = tail.len();
367
368 Ok(input.len())
369 }
370
371 fn flush(&mut self) -> io::Result<()> {
372 self.inner.flush()
373 }
374 }
375
376 fn decode_error_to_io(err: DecodeError) -> io::Error {
377 io::Error::new(io::ErrorKind::InvalidInput, err)
378 }
379
380 fn trailing_input_after_padding_error() -> io::Error {
381 io::Error::new(
382 io::ErrorKind::InvalidInput,
383 "base64 decoder received trailing input after padding",
384 )
385 }
386
387 pub struct DecoderReader<R, A, const PAD: bool>
394 where
395 A: Alphabet,
396 {
397 inner: R,
398 engine: Engine<A, PAD>,
399 pending: [u8; 4],
400 pending_len: usize,
401 output: VecDeque<u8>,
402 finished: bool,
403 terminal_seen: bool,
404 }
405
406 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
407 where
408 A: Alphabet,
409 {
410 #[must_use]
412 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
413 Self {
414 inner,
415 engine,
416 pending: [0; 4],
417 pending_len: 0,
418 output: VecDeque::new(),
419 finished: false,
420 terminal_seen: false,
421 }
422 }
423
424 #[must_use]
426 pub const fn get_ref(&self) -> &R {
427 &self.inner
428 }
429
430 pub fn get_mut(&mut self) -> &mut R {
432 &mut self.inner
433 }
434
435 #[must_use]
437 pub fn into_inner(self) -> R {
438 self.inner
439 }
440 }
441
442 impl<R, A, const PAD: bool> Read for DecoderReader<R, A, PAD>
443 where
444 R: Read,
445 A: Alphabet,
446 {
447 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
448 if output.is_empty() {
449 return Ok(0);
450 }
451
452 while self.output.is_empty() && !self.finished {
453 self.fill_output()?;
454 }
455
456 let mut written = 0;
457 while written < output.len() {
458 let Some(byte) = self.output.pop_front() else {
459 break;
460 };
461 output[written] = byte;
462 written += 1;
463 }
464
465 Ok(written)
466 }
467 }
468
469 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
470 where
471 R: Read,
472 A: Alphabet,
473 {
474 fn fill_output(&mut self) -> io::Result<()> {
475 if self.terminal_seen {
476 self.finished = true;
477 return Ok(());
478 }
479
480 let mut input = [0u8; 4];
481 let read = self.inner.read(&mut input[..4 - self.pending_len])?;
482 if read == 0 {
483 self.finished = true;
484 self.push_final_pending()?;
485 return Ok(());
486 }
487
488 self.pending[self.pending_len..self.pending_len + read].copy_from_slice(&input[..read]);
489 self.pending_len += read;
490 if self.pending_len < 4 {
491 return Ok(());
492 }
493
494 let quad = self.pending;
495 self.pending_len = 0;
496 self.push_decoded(&quad)?;
497 if self.terminal_seen {
498 self.finished = true;
499 }
500 Ok(())
501 }
502
503 fn push_final_pending(&mut self) -> io::Result<()> {
504 if self.pending_len == 0 {
505 return Ok(());
506 }
507
508 let mut pending = [0u8; 4];
509 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
510 let pending_len = self.pending_len;
511 self.pending_len = 0;
512 self.push_decoded(&pending[..pending_len])
513 }
514
515 fn push_decoded(&mut self, input: &[u8]) -> io::Result<()> {
516 let mut decoded = [0u8; 3];
517 let written = self
518 .engine
519 .decode_slice(input, &mut decoded)
520 .map_err(decode_error_to_io)?;
521 self.output.extend(&decoded[..written]);
522 if input.len() == 4 && written < 3 {
523 self.terminal_seen = true;
524 }
525 Ok(())
526 }
527 }
528
529 pub struct EncoderReader<R, A, const PAD: bool>
531 where
532 A: Alphabet,
533 {
534 inner: R,
535 engine: Engine<A, PAD>,
536 pending: [u8; 2],
537 pending_len: usize,
538 output: VecDeque<u8>,
539 finished: bool,
540 }
541
542 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
543 where
544 A: Alphabet,
545 {
546 #[must_use]
548 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
549 Self {
550 inner,
551 engine,
552 pending: [0; 2],
553 pending_len: 0,
554 output: VecDeque::new(),
555 finished: false,
556 }
557 }
558
559 #[must_use]
561 pub const fn get_ref(&self) -> &R {
562 &self.inner
563 }
564
565 pub fn get_mut(&mut self) -> &mut R {
567 &mut self.inner
568 }
569
570 #[must_use]
572 pub fn into_inner(self) -> R {
573 self.inner
574 }
575 }
576
577 impl<R, A, const PAD: bool> Read for EncoderReader<R, A, PAD>
578 where
579 R: Read,
580 A: Alphabet,
581 {
582 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
583 if output.is_empty() {
584 return Ok(0);
585 }
586
587 while self.output.is_empty() && !self.finished {
588 self.fill_output()?;
589 }
590
591 let mut written = 0;
592 while written < output.len() {
593 let Some(byte) = self.output.pop_front() else {
594 break;
595 };
596 output[written] = byte;
597 written += 1;
598 }
599
600 Ok(written)
601 }
602 }
603
604 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
605 where
606 R: Read,
607 A: Alphabet,
608 {
609 fn fill_output(&mut self) -> io::Result<()> {
610 let mut input = [0u8; 768];
611 let read = self.inner.read(&mut input)?;
612 if read == 0 {
613 self.finished = true;
614 self.push_final_pending()?;
615 return Ok(());
616 }
617
618 let mut consumed = 0;
619 if self.pending_len > 0 {
620 let needed = 3 - self.pending_len;
621 if read < needed {
622 self.pending[self.pending_len..self.pending_len + read]
623 .copy_from_slice(&input[..read]);
624 self.pending_len += read;
625 return Ok(());
626 }
627
628 let mut chunk = [0u8; 3];
629 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
630 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
631 self.push_encoded(&chunk)?;
632 self.pending_len = 0;
633 consumed += needed;
634 }
635
636 let remaining = &input[consumed..read];
637 let full_len = remaining.len() / 3 * 3;
638 if full_len > 0 {
639 self.push_encoded(&remaining[..full_len])?;
640 }
641
642 let tail = &remaining[full_len..];
643 self.pending[..tail.len()].copy_from_slice(tail);
644 self.pending_len = tail.len();
645 Ok(())
646 }
647
648 fn push_final_pending(&mut self) -> io::Result<()> {
649 if self.pending_len == 0 {
650 return Ok(());
651 }
652
653 let mut pending = [0u8; 2];
654 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
655 let pending_len = self.pending_len;
656 self.pending_len = 0;
657 self.push_encoded(&pending[..pending_len])
658 }
659
660 fn push_encoded(&mut self, input: &[u8]) -> io::Result<()> {
661 let mut encoded = [0u8; 1024];
662 let written = self
663 .engine
664 .encode_slice(input, &mut encoded)
665 .map_err(encode_error_to_io)?;
666 self.output.extend(&encoded[..written]);
667 Ok(())
668 }
669 }
670}
671
672pub mod ct {
679 use super::{Alphabet, DecodeError, Standard, UrlSafe, ct_decode_slice};
680 use core::marker::PhantomData;
681
682 pub const STANDARD: CtEngine<Standard, true> = CtEngine::new();
684
685 pub const STANDARD_NO_PAD: CtEngine<Standard, false> = CtEngine::new();
687
688 pub const URL_SAFE: CtEngine<UrlSafe, true> = CtEngine::new();
690
691 pub const URL_SAFE_NO_PAD: CtEngine<UrlSafe, false> = CtEngine::new();
693
694 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
696 pub struct CtEngine<A, const PAD: bool> {
697 alphabet: PhantomData<A>,
698 }
699
700 impl<A, const PAD: bool> CtEngine<A, PAD>
701 where
702 A: Alphabet,
703 {
704 #[must_use]
706 pub const fn new() -> Self {
707 Self {
708 alphabet: PhantomData,
709 }
710 }
711
712 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
734 ct_decode_slice::<A, PAD>(input, output)
735 }
736 }
737}
738
739pub const STANDARD: Engine<Standard, true> = Engine::new();
741
742pub const STANDARD_NO_PAD: Engine<Standard, false> = Engine::new();
744
745pub const URL_SAFE: Engine<UrlSafe, true> = Engine::new();
747
748pub const URL_SAFE_NO_PAD: Engine<UrlSafe, false> = Engine::new();
750
751pub const fn encoded_len(input_len: usize, padded: bool) -> Result<usize, EncodeError> {
766 match checked_encoded_len(input_len, padded) {
767 Some(len) => Ok(len),
768 None => Err(EncodeError::LengthOverflow),
769 }
770}
771
772#[must_use]
783pub const fn checked_encoded_len(input_len: usize, padded: bool) -> Option<usize> {
784 let groups = input_len / 3;
785 if groups > usize::MAX / 4 {
786 return None;
787 }
788 let full = groups * 4;
789 let rem = input_len % 3;
790 if rem == 0 {
791 Some(full)
792 } else if padded {
793 full.checked_add(4)
794 } else {
795 full.checked_add(rem + 1)
796 }
797}
798
799#[must_use]
810pub const fn decoded_capacity(encoded_len: usize) -> usize {
811 let rem = encoded_len % 4;
812 encoded_len / 4 * 3
813 + if rem == 2 {
814 1
815 } else if rem == 3 {
816 2
817 } else {
818 0
819 }
820}
821
822pub fn decoded_len(input: &[u8], padded: bool) -> Result<usize, DecodeError> {
836 if padded {
837 decoded_len_padded(input)
838 } else {
839 decoded_len_unpadded(input)
840 }
841}
842
843pub trait Alphabet {
845 const ENCODE: [u8; 64];
847
848 fn decode(byte: u8) -> Option<u8>;
850}
851
852#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
854pub struct Standard;
855
856impl Alphabet for Standard {
857 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
858
859 #[inline]
860 fn decode(byte: u8) -> Option<u8> {
861 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
862 }
863}
864
865#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
867pub struct UrlSafe;
868
869impl Alphabet for UrlSafe {
870 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
871
872 #[inline]
873 fn decode(byte: u8) -> Option<u8> {
874 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
875 }
876}
877
878#[inline]
879const fn encode_base64_value<A: Alphabet>(value: u8) -> u8 {
880 encode_ascii_base64(value, A::ENCODE[62], A::ENCODE[63])
881}
882
883#[inline]
884const fn encode_ascii_base64(value: u8, value_62_byte: u8, value_63_byte: u8) -> u8 {
885 let upper = mask_if(value < 26);
886 let lower = mask_if(value.wrapping_sub(26) < 26);
887 let digit = mask_if(value.wrapping_sub(52) < 10);
888 let value_62 = mask_if(value == 0x3e);
889 let value_63 = mask_if(value == 0x3f);
890
891 (value.wrapping_add(b'A') & upper)
892 | (value.wrapping_sub(26).wrapping_add(b'a') & lower)
893 | (value.wrapping_sub(52).wrapping_add(b'0') & digit)
894 | (value_62_byte & value_62)
895 | (value_63_byte & value_63)
896}
897
898#[inline]
899fn decode_ascii_base64(byte: u8, value_62_byte: u8, value_63_byte: u8) -> Option<u8> {
900 let upper = mask_if(byte.wrapping_sub(b'A') <= b'Z' - b'A');
901 let lower = mask_if(byte.wrapping_sub(b'a') <= b'z' - b'a');
902 let digit = mask_if(byte.wrapping_sub(b'0') <= b'9' - b'0');
903 let value_62 = mask_if(byte == value_62_byte);
904 let value_63 = mask_if(byte == value_63_byte);
905 let valid = upper | lower | digit | value_62 | value_63;
906
907 let decoded = (byte.wrapping_sub(b'A') & upper)
908 | (byte.wrapping_sub(b'a').wrapping_add(26) & lower)
909 | (byte.wrapping_sub(b'0').wrapping_add(52) & digit)
910 | (0x3e & value_62)
911 | (0x3f & value_63);
912
913 if valid == 0 { None } else { Some(decoded) }
914}
915
916#[inline]
917const fn mask_if(condition: bool) -> u8 {
918 0u8.wrapping_sub(condition as u8)
919}
920
921#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
923pub struct Engine<A, const PAD: bool> {
924 alphabet: core::marker::PhantomData<A>,
925}
926
927impl<A, const PAD: bool> Engine<A, PAD>
928where
929 A: Alphabet,
930{
931 #[must_use]
933 pub const fn new() -> Self {
934 Self {
935 alphabet: core::marker::PhantomData,
936 }
937 }
938
939 pub const fn encoded_len(&self, input_len: usize) -> Result<usize, EncodeError> {
941 encoded_len(input_len, PAD)
942 }
943
944 #[must_use]
946 pub const fn checked_encoded_len(&self, input_len: usize) -> Option<usize> {
947 checked_encoded_len(input_len, PAD)
948 }
949
950 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
955 decoded_len(input, PAD)
956 }
957
958 pub fn decoded_len_legacy(&self, input: &[u8]) -> Result<usize, DecodeError> {
964 validate_legacy_decode::<A, PAD>(input)
965 }
966
967 #[must_use]
999 pub const fn encode_array<const INPUT_LEN: usize, const OUTPUT_LEN: usize>(
1000 &self,
1001 input: &[u8; INPUT_LEN],
1002 ) -> [u8; OUTPUT_LEN] {
1003 let Some(required) = checked_encoded_len(INPUT_LEN, PAD) else {
1004 panic!("encoded base64 length overflows usize");
1005 };
1006 assert!(
1007 required == OUTPUT_LEN,
1008 "base64 output array has incorrect length"
1009 );
1010
1011 let mut output = [0u8; OUTPUT_LEN];
1012 let mut read = 0;
1013 let mut write = 0;
1014 while INPUT_LEN - read >= 3 {
1015 let b0 = input[read];
1016 let b1 = input[read + 1];
1017 let b2 = input[read + 2];
1018
1019 output[write] = encode_base64_value::<A>(b0 >> 2);
1020 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1021 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1022 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1023
1024 read += 3;
1025 write += 4;
1026 }
1027
1028 match INPUT_LEN - read {
1029 0 => {}
1030 1 => {
1031 let b0 = input[read];
1032 output[write] = encode_base64_value::<A>(b0 >> 2);
1033 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1034 write += 2;
1035 if PAD {
1036 output[write] = b'=';
1037 output[write + 1] = b'=';
1038 }
1039 }
1040 2 => {
1041 let b0 = input[read];
1042 let b1 = input[read + 1];
1043 output[write] = encode_base64_value::<A>(b0 >> 2);
1044 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1045 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1046 if PAD {
1047 output[write + 3] = b'=';
1048 }
1049 }
1050 _ => unreachable!(),
1051 }
1052
1053 output
1054 }
1055
1056 pub fn encode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
1058 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
1059 if output.len() < required {
1060 return Err(EncodeError::OutputTooSmall {
1061 required,
1062 available: output.len(),
1063 });
1064 }
1065
1066 let mut read = 0;
1067 let mut write = 0;
1068 while read + 3 <= input.len() {
1069 let b0 = input[read];
1070 let b1 = input[read + 1];
1071 let b2 = input[read + 2];
1072
1073 output[write] = encode_base64_value::<A>(b0 >> 2);
1074 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1075 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1076 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1077
1078 read += 3;
1079 write += 4;
1080 }
1081
1082 match input.len() - read {
1083 0 => {}
1084 1 => {
1085 let b0 = input[read];
1086 output[write] = encode_base64_value::<A>(b0 >> 2);
1087 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1088 write += 2;
1089 if PAD {
1090 output[write] = b'=';
1091 output[write + 1] = b'=';
1092 write += 2;
1093 }
1094 }
1095 2 => {
1096 let b0 = input[read];
1097 let b1 = input[read + 1];
1098 output[write] = encode_base64_value::<A>(b0 >> 2);
1099 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1100 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1101 write += 3;
1102 if PAD {
1103 output[write] = b'=';
1104 write += 1;
1105 }
1106 }
1107 _ => unreachable!(),
1108 }
1109
1110 Ok(write)
1111 }
1112
1113 pub fn encode_slice_clear_tail(
1133 &self,
1134 input: &[u8],
1135 output: &mut [u8],
1136 ) -> Result<usize, EncodeError> {
1137 let written = match self.encode_slice(input, output) {
1138 Ok(written) => written,
1139 Err(err) => {
1140 output.fill(0);
1141 return Err(err);
1142 }
1143 };
1144 output[written..].fill(0);
1145 Ok(written)
1146 }
1147
1148 #[cfg(feature = "alloc")]
1150 pub fn encode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
1151 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
1152 let mut output = alloc::vec![0; required];
1153 let written = self.encode_slice(input, &mut output)?;
1154 output.truncate(written);
1155 Ok(output)
1156 }
1157
1158 #[cfg(feature = "alloc")]
1173 pub fn encode_string(&self, input: &[u8]) -> Result<alloc::string::String, EncodeError> {
1174 let output = self.encode_vec(input)?;
1175 match alloc::string::String::from_utf8(output) {
1176 Ok(output) => Ok(output),
1177 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
1178 }
1179 }
1180
1181 pub fn encode_in_place<'a>(
1198 &self,
1199 buffer: &'a mut [u8],
1200 input_len: usize,
1201 ) -> Result<&'a mut [u8], EncodeError> {
1202 if input_len > buffer.len() {
1203 return Err(EncodeError::InputTooLarge {
1204 input_len,
1205 buffer_len: buffer.len(),
1206 });
1207 }
1208
1209 let required = checked_encoded_len(input_len, PAD).ok_or(EncodeError::LengthOverflow)?;
1210 if buffer.len() < required {
1211 return Err(EncodeError::OutputTooSmall {
1212 required,
1213 available: buffer.len(),
1214 });
1215 }
1216
1217 let mut read = input_len;
1218 let mut write = required;
1219
1220 match input_len % 3 {
1221 0 => {}
1222 1 => {
1223 read -= 1;
1224 let b0 = buffer[read];
1225 if PAD {
1226 write -= 4;
1227 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1228 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1229 buffer[write + 2] = b'=';
1230 buffer[write + 3] = b'=';
1231 } else {
1232 write -= 2;
1233 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1234 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1235 }
1236 }
1237 2 => {
1238 read -= 2;
1239 let b0 = buffer[read];
1240 let b1 = buffer[read + 1];
1241 if PAD {
1242 write -= 4;
1243 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1244 buffer[write + 1] =
1245 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1246 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1247 buffer[write + 3] = b'=';
1248 } else {
1249 write -= 3;
1250 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1251 buffer[write + 1] =
1252 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1253 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1254 }
1255 }
1256 _ => unreachable!(),
1257 }
1258
1259 while read > 0 {
1260 read -= 3;
1261 write -= 4;
1262 let b0 = buffer[read];
1263 let b1 = buffer[read + 1];
1264 let b2 = buffer[read + 2];
1265
1266 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1267 buffer[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1268 buffer[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1269 buffer[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1270 }
1271
1272 debug_assert_eq!(write, 0);
1273 Ok(&mut buffer[..required])
1274 }
1275
1276 pub fn encode_in_place_clear_tail<'a>(
1294 &self,
1295 buffer: &'a mut [u8],
1296 input_len: usize,
1297 ) -> Result<&'a mut [u8], EncodeError> {
1298 let len = match self.encode_in_place(buffer, input_len) {
1299 Ok(encoded) => encoded.len(),
1300 Err(err) => {
1301 buffer.fill(0);
1302 return Err(err);
1303 }
1304 };
1305 buffer[len..].fill(0);
1306 Ok(&mut buffer[..len])
1307 }
1308
1309 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1314 if input.is_empty() {
1315 return Ok(0);
1316 }
1317
1318 if PAD {
1319 decode_padded::<A>(input, output)
1320 } else {
1321 decode_unpadded::<A>(input, output)
1322 }
1323 }
1324
1325 pub fn decode_slice_clear_tail(
1345 &self,
1346 input: &[u8],
1347 output: &mut [u8],
1348 ) -> Result<usize, DecodeError> {
1349 let written = match self.decode_slice(input, output) {
1350 Ok(written) => written,
1351 Err(err) => {
1352 output.fill(0);
1353 return Err(err);
1354 }
1355 };
1356 output[written..].fill(0);
1357 Ok(written)
1358 }
1359
1360 pub fn decode_slice_legacy(
1366 &self,
1367 input: &[u8],
1368 output: &mut [u8],
1369 ) -> Result<usize, DecodeError> {
1370 let required = validate_legacy_decode::<A, PAD>(input)?;
1371 if output.len() < required {
1372 return Err(DecodeError::OutputTooSmall {
1373 required,
1374 available: output.len(),
1375 });
1376 }
1377 decode_legacy_to_slice::<A, PAD>(input, output)
1378 }
1379
1380 pub fn decode_slice_legacy_clear_tail(
1400 &self,
1401 input: &[u8],
1402 output: &mut [u8],
1403 ) -> Result<usize, DecodeError> {
1404 let written = match self.decode_slice_legacy(input, output) {
1405 Ok(written) => written,
1406 Err(err) => {
1407 output.fill(0);
1408 return Err(err);
1409 }
1410 };
1411 output[written..].fill(0);
1412 Ok(written)
1413 }
1414
1415 #[cfg(feature = "alloc")]
1419 pub fn decode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
1420 let required = validate_decode::<A, PAD>(input)?;
1421 let mut output = alloc::vec![0; required];
1422 let written = match self.decode_slice(input, &mut output) {
1423 Ok(written) => written,
1424 Err(err) => {
1425 output.fill(0);
1426 return Err(err);
1427 }
1428 };
1429 output.truncate(written);
1430 Ok(output)
1431 }
1432
1433 #[cfg(feature = "alloc")]
1436 pub fn decode_vec_legacy(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
1437 let required = validate_legacy_decode::<A, PAD>(input)?;
1438 let mut output = alloc::vec![0; required];
1439 let written = match self.decode_slice_legacy(input, &mut output) {
1440 Ok(written) => written,
1441 Err(err) => {
1442 output.fill(0);
1443 return Err(err);
1444 }
1445 };
1446 output.truncate(written);
1447 Ok(output)
1448 }
1449
1450 pub fn decode_in_place<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], DecodeError> {
1462 let len = Self::decode_slice_to_start(buffer)?;
1463 Ok(&mut buffer[..len])
1464 }
1465
1466 pub fn decode_in_place_clear_tail<'a>(
1483 &self,
1484 buffer: &'a mut [u8],
1485 ) -> Result<&'a mut [u8], DecodeError> {
1486 let len = match Self::decode_slice_to_start(buffer) {
1487 Ok(len) => len,
1488 Err(err) => {
1489 buffer.fill(0);
1490 return Err(err);
1491 }
1492 };
1493 buffer[len..].fill(0);
1494 Ok(&mut buffer[..len])
1495 }
1496
1497 pub fn decode_in_place_legacy<'a>(
1502 &self,
1503 buffer: &'a mut [u8],
1504 ) -> Result<&'a mut [u8], DecodeError> {
1505 let _required = validate_legacy_decode::<A, PAD>(buffer)?;
1506 let mut write = 0;
1507 let mut read = 0;
1508 while read < buffer.len() {
1509 let byte = buffer[read];
1510 if !is_legacy_whitespace(byte) {
1511 buffer[write] = byte;
1512 write += 1;
1513 }
1514 read += 1;
1515 }
1516 let len = Self::decode_slice_to_start(&mut buffer[..write])?;
1517 Ok(&mut buffer[..len])
1518 }
1519
1520 pub fn decode_in_place_legacy_clear_tail<'a>(
1526 &self,
1527 buffer: &'a mut [u8],
1528 ) -> Result<&'a mut [u8], DecodeError> {
1529 if let Err(err) = validate_legacy_decode::<A, PAD>(buffer) {
1530 buffer.fill(0);
1531 return Err(err);
1532 }
1533
1534 let mut write = 0;
1535 let mut read = 0;
1536 while read < buffer.len() {
1537 let byte = buffer[read];
1538 if !is_legacy_whitespace(byte) {
1539 buffer[write] = byte;
1540 write += 1;
1541 }
1542 read += 1;
1543 }
1544
1545 let len = match Self::decode_slice_to_start(&mut buffer[..write]) {
1546 Ok(len) => len,
1547 Err(err) => {
1548 buffer.fill(0);
1549 return Err(err);
1550 }
1551 };
1552 buffer[len..].fill(0);
1553 Ok(&mut buffer[..len])
1554 }
1555
1556 fn decode_slice_to_start(buffer: &mut [u8]) -> Result<usize, DecodeError> {
1557 let input_len = buffer.len();
1558 let mut read = 0;
1559 let mut write = 0;
1560 while read + 4 <= input_len {
1561 let chunk = [
1562 buffer[read],
1563 buffer[read + 1],
1564 buffer[read + 2],
1565 buffer[read + 3],
1566 ];
1567 let written = decode_chunk::<A, PAD>(&chunk, &mut buffer[write..])
1568 .map_err(|err| err.with_index_offset(read))?;
1569 read += 4;
1570 write += written;
1571 if written < 3 {
1572 if read != input_len {
1573 return Err(DecodeError::InvalidPadding { index: read - 4 });
1574 }
1575 return Ok(write);
1576 }
1577 }
1578
1579 let rem = input_len - read;
1580 if rem == 0 {
1581 return Ok(write);
1582 }
1583 if PAD {
1584 return Err(DecodeError::InvalidLength);
1585 }
1586 let mut tail = [0u8; 3];
1587 tail[..rem].copy_from_slice(&buffer[read..input_len]);
1588 decode_tail_unpadded::<A>(&tail[..rem], &mut buffer[write..])
1589 .map_err(|err| err.with_index_offset(read))
1590 .map(|n| write + n)
1591 }
1592}
1593
1594#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1596pub enum EncodeError {
1597 LengthOverflow,
1599 InputTooLarge {
1601 input_len: usize,
1603 buffer_len: usize,
1605 },
1606 OutputTooSmall {
1608 required: usize,
1610 available: usize,
1612 },
1613}
1614
1615impl core::fmt::Display for EncodeError {
1616 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1617 match self {
1618 Self::LengthOverflow => f.write_str("base64 output length overflows usize"),
1619 Self::InputTooLarge {
1620 input_len,
1621 buffer_len,
1622 } => write!(
1623 f,
1624 "base64 input length {input_len} exceeds buffer length {buffer_len}"
1625 ),
1626 Self::OutputTooSmall {
1627 required,
1628 available,
1629 } => write!(
1630 f,
1631 "base64 output buffer too small: required {required}, available {available}"
1632 ),
1633 }
1634 }
1635}
1636
1637#[cfg(feature = "std")]
1638impl std::error::Error for EncodeError {}
1639
1640#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1642pub enum DecodeError {
1643 InvalidLength,
1645 InvalidByte {
1647 index: usize,
1649 byte: u8,
1651 },
1652 InvalidPadding {
1654 index: usize,
1656 },
1657 OutputTooSmall {
1659 required: usize,
1661 available: usize,
1663 },
1664}
1665
1666impl core::fmt::Display for DecodeError {
1667 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1668 match self {
1669 Self::InvalidLength => f.write_str("invalid base64 input length"),
1670 Self::InvalidByte { index, byte } => {
1671 write!(f, "invalid base64 byte 0x{byte:02x} at index {index}")
1672 }
1673 Self::InvalidPadding { index } => write!(f, "invalid base64 padding at index {index}"),
1674 Self::OutputTooSmall {
1675 required,
1676 available,
1677 } => write!(
1678 f,
1679 "base64 decode output buffer too small: required {required}, available {available}"
1680 ),
1681 }
1682 }
1683}
1684
1685impl DecodeError {
1686 fn with_index_offset(self, offset: usize) -> Self {
1687 match self {
1688 Self::InvalidByte { index, byte } => Self::InvalidByte {
1689 index: index + offset,
1690 byte,
1691 },
1692 Self::InvalidPadding { index } => Self::InvalidPadding {
1693 index: index + offset,
1694 },
1695 Self::InvalidLength | Self::OutputTooSmall { .. } => self,
1696 }
1697 }
1698}
1699
1700#[cfg(feature = "std")]
1701impl std::error::Error for DecodeError {}
1702
1703fn validate_legacy_decode<A: Alphabet, const PAD: bool>(
1704 input: &[u8],
1705) -> Result<usize, DecodeError> {
1706 let mut chunk = [0u8; 4];
1707 let mut indexes = [0usize; 4];
1708 let mut chunk_len = 0;
1709 let mut required = 0;
1710 let mut terminal_seen = false;
1711
1712 for (index, byte) in input.iter().copied().enumerate() {
1713 if is_legacy_whitespace(byte) {
1714 continue;
1715 }
1716 if terminal_seen {
1717 return Err(DecodeError::InvalidPadding { index });
1718 }
1719
1720 chunk[chunk_len] = byte;
1721 indexes[chunk_len] = index;
1722 chunk_len += 1;
1723
1724 if chunk_len == 4 {
1725 let written =
1726 validate_chunk::<A, PAD>(&chunk).map_err(|err| map_chunk_error(err, &indexes))?;
1727 required += written;
1728 terminal_seen = written < 3;
1729 chunk_len = 0;
1730 }
1731 }
1732
1733 if chunk_len == 0 {
1734 return Ok(required);
1735 }
1736 if PAD {
1737 return Err(DecodeError::InvalidLength);
1738 }
1739
1740 validate_tail_unpadded::<A>(&chunk[..chunk_len])
1741 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))?;
1742 Ok(required + decoded_capacity(chunk_len))
1743}
1744
1745fn decode_legacy_to_slice<A: Alphabet, const PAD: bool>(
1746 input: &[u8],
1747 output: &mut [u8],
1748) -> Result<usize, DecodeError> {
1749 let mut chunk = [0u8; 4];
1750 let mut indexes = [0usize; 4];
1751 let mut chunk_len = 0;
1752 let mut write = 0;
1753 let mut terminal_seen = false;
1754
1755 for (index, byte) in input.iter().copied().enumerate() {
1756 if is_legacy_whitespace(byte) {
1757 continue;
1758 }
1759 if terminal_seen {
1760 return Err(DecodeError::InvalidPadding { index });
1761 }
1762
1763 chunk[chunk_len] = byte;
1764 indexes[chunk_len] = index;
1765 chunk_len += 1;
1766
1767 if chunk_len == 4 {
1768 let written = decode_chunk::<A, PAD>(&chunk, &mut output[write..])
1769 .map_err(|err| map_chunk_error(err, &indexes))?;
1770 write += written;
1771 terminal_seen = written < 3;
1772 chunk_len = 0;
1773 }
1774 }
1775
1776 if chunk_len == 0 {
1777 return Ok(write);
1778 }
1779 if PAD {
1780 return Err(DecodeError::InvalidLength);
1781 }
1782
1783 decode_tail_unpadded::<A>(&chunk[..chunk_len], &mut output[write..])
1784 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))
1785 .map(|n| write + n)
1786}
1787
1788#[inline]
1789const fn is_legacy_whitespace(byte: u8) -> bool {
1790 matches!(byte, b' ' | b'\t' | b'\r' | b'\n')
1791}
1792
1793fn map_chunk_error(err: DecodeError, indexes: &[usize; 4]) -> DecodeError {
1794 match err {
1795 DecodeError::InvalidByte { index, byte } => DecodeError::InvalidByte {
1796 index: indexes[index],
1797 byte,
1798 },
1799 DecodeError::InvalidPadding { index } => DecodeError::InvalidPadding {
1800 index: indexes[index],
1801 },
1802 DecodeError::InvalidLength | DecodeError::OutputTooSmall { .. } => err,
1803 }
1804}
1805
1806fn map_partial_chunk_error(err: DecodeError, indexes: &[usize; 4], len: usize) -> DecodeError {
1807 match err {
1808 DecodeError::InvalidByte { index, byte } if index < len => DecodeError::InvalidByte {
1809 index: indexes[index],
1810 byte,
1811 },
1812 DecodeError::InvalidPadding { index } if index < len => DecodeError::InvalidPadding {
1813 index: indexes[index],
1814 },
1815 DecodeError::InvalidByte { .. }
1816 | DecodeError::InvalidPadding { .. }
1817 | DecodeError::InvalidLength
1818 | DecodeError::OutputTooSmall { .. } => err,
1819 }
1820}
1821
1822fn decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1823 if !input.len().is_multiple_of(4) {
1824 return Err(DecodeError::InvalidLength);
1825 }
1826 let required = decoded_len_padded(input)?;
1827 if output.len() < required {
1828 return Err(DecodeError::OutputTooSmall {
1829 required,
1830 available: output.len(),
1831 });
1832 }
1833
1834 let mut read = 0;
1835 let mut write = 0;
1836 while read < input.len() {
1837 let written = decode_chunk::<A, true>(&input[read..read + 4], &mut output[write..])
1838 .map_err(|err| err.with_index_offset(read))?;
1839 read += 4;
1840 write += written;
1841 if written < 3 && read != input.len() {
1842 return Err(DecodeError::InvalidPadding { index: read - 4 });
1843 }
1844 }
1845 Ok(write)
1846}
1847
1848#[cfg(feature = "alloc")]
1849fn validate_decode<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1850 if input.is_empty() {
1851 return Ok(0);
1852 }
1853
1854 if PAD {
1855 validate_padded::<A>(input)
1856 } else {
1857 validate_unpadded::<A>(input)
1858 }
1859}
1860
1861#[cfg(feature = "alloc")]
1862fn validate_padded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1863 if !input.len().is_multiple_of(4) {
1864 return Err(DecodeError::InvalidLength);
1865 }
1866 let required = decoded_len_padded(input)?;
1867
1868 let mut read = 0;
1869 while read < input.len() {
1870 let written = validate_chunk::<A, true>(&input[read..read + 4])
1871 .map_err(|err| err.with_index_offset(read))?;
1872 read += 4;
1873 if written < 3 && read != input.len() {
1874 return Err(DecodeError::InvalidPadding { index: read - 4 });
1875 }
1876 }
1877
1878 Ok(required)
1879}
1880
1881#[cfg(feature = "alloc")]
1882fn validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1883 let required = decoded_len_unpadded(input)?;
1884
1885 let mut read = 0;
1886 while read + 4 <= input.len() {
1887 validate_chunk::<A, false>(&input[read..read + 4])
1888 .map_err(|err| err.with_index_offset(read))?;
1889 read += 4;
1890 }
1891 validate_tail_unpadded::<A>(&input[read..]).map_err(|err| err.with_index_offset(read))?;
1892
1893 Ok(required)
1894}
1895
1896fn decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1897 let required = decoded_len_unpadded(input)?;
1898 if output.len() < required {
1899 return Err(DecodeError::OutputTooSmall {
1900 required,
1901 available: output.len(),
1902 });
1903 }
1904
1905 let mut read = 0;
1906 let mut write = 0;
1907 while read + 4 <= input.len() {
1908 let written = decode_chunk::<A, false>(&input[read..read + 4], &mut output[write..])
1909 .map_err(|err| err.with_index_offset(read))?;
1910 read += 4;
1911 write += written;
1912 }
1913 decode_tail_unpadded::<A>(&input[read..], &mut output[write..])
1914 .map_err(|err| err.with_index_offset(read))
1915 .map(|n| write + n)
1916}
1917
1918fn decoded_len_padded(input: &[u8]) -> Result<usize, DecodeError> {
1919 if input.is_empty() {
1920 return Ok(0);
1921 }
1922 if !input.len().is_multiple_of(4) {
1923 return Err(DecodeError::InvalidLength);
1924 }
1925 let mut padding = 0;
1926 if input[input.len() - 1] == b'=' {
1927 padding += 1;
1928 }
1929 if input[input.len() - 2] == b'=' {
1930 padding += 1;
1931 }
1932 if padding == 0
1933 && let Some(index) = input.iter().position(|byte| *byte == b'=')
1934 {
1935 return Err(DecodeError::InvalidPadding { index });
1936 }
1937 if padding > 0 {
1938 let first_pad = input.len() - padding;
1939 if let Some(index) = input[..first_pad].iter().position(|byte| *byte == b'=') {
1940 return Err(DecodeError::InvalidPadding { index });
1941 }
1942 }
1943 Ok(input.len() / 4 * 3 - padding)
1944}
1945
1946fn decoded_len_unpadded(input: &[u8]) -> Result<usize, DecodeError> {
1947 if input.len() % 4 == 1 {
1948 return Err(DecodeError::InvalidLength);
1949 }
1950 if let Some(index) = input.iter().position(|byte| *byte == b'=') {
1951 return Err(DecodeError::InvalidPadding { index });
1952 }
1953 Ok(decoded_capacity(input.len()))
1954}
1955
1956fn validate_chunk<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1957 debug_assert_eq!(input.len(), 4);
1958 let _v0 = decode_byte::<A>(input[0], 0)?;
1959 let v1 = decode_byte::<A>(input[1], 1)?;
1960
1961 match (input[2], input[3]) {
1962 (b'=', b'=') if PAD => {
1963 if v1 & 0b0000_1111 != 0 {
1964 return Err(DecodeError::InvalidPadding { index: 1 });
1965 }
1966 Ok(1)
1967 }
1968 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
1969 (_, b'=') if PAD => {
1970 let v2 = decode_byte::<A>(input[2], 2)?;
1971 if v2 & 0b0000_0011 != 0 {
1972 return Err(DecodeError::InvalidPadding { index: 2 });
1973 }
1974 Ok(2)
1975 }
1976 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
1977 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
1978 }),
1979 _ => {
1980 decode_byte::<A>(input[2], 2)?;
1981 decode_byte::<A>(input[3], 3)?;
1982 Ok(3)
1983 }
1984 }
1985}
1986
1987fn decode_chunk<A: Alphabet, const PAD: bool>(
1988 input: &[u8],
1989 output: &mut [u8],
1990) -> Result<usize, DecodeError> {
1991 debug_assert_eq!(input.len(), 4);
1992 let v0 = decode_byte::<A>(input[0], 0)?;
1993 let v1 = decode_byte::<A>(input[1], 1)?;
1994
1995 match (input[2], input[3]) {
1996 (b'=', b'=') if PAD => {
1997 if output.is_empty() {
1998 return Err(DecodeError::OutputTooSmall {
1999 required: 1,
2000 available: output.len(),
2001 });
2002 }
2003 if v1 & 0b0000_1111 != 0 {
2004 return Err(DecodeError::InvalidPadding { index: 1 });
2005 }
2006 output[0] = (v0 << 2) | (v1 >> 4);
2007 Ok(1)
2008 }
2009 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
2010 (_, b'=') if PAD => {
2011 if output.len() < 2 {
2012 return Err(DecodeError::OutputTooSmall {
2013 required: 2,
2014 available: output.len(),
2015 });
2016 }
2017 let v2 = decode_byte::<A>(input[2], 2)?;
2018 if v2 & 0b0000_0011 != 0 {
2019 return Err(DecodeError::InvalidPadding { index: 2 });
2020 }
2021 output[0] = (v0 << 2) | (v1 >> 4);
2022 output[1] = (v1 << 4) | (v2 >> 2);
2023 Ok(2)
2024 }
2025 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
2026 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
2027 }),
2028 _ => {
2029 if output.len() < 3 {
2030 return Err(DecodeError::OutputTooSmall {
2031 required: 3,
2032 available: output.len(),
2033 });
2034 }
2035 let v2 = decode_byte::<A>(input[2], 2)?;
2036 let v3 = decode_byte::<A>(input[3], 3)?;
2037 output[0] = (v0 << 2) | (v1 >> 4);
2038 output[1] = (v1 << 4) | (v2 >> 2);
2039 output[2] = (v2 << 6) | v3;
2040 Ok(3)
2041 }
2042 }
2043}
2044
2045fn validate_tail_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
2046 match input.len() {
2047 0 => Ok(()),
2048 2 => {
2049 decode_byte::<A>(input[0], 0)?;
2050 let v1 = decode_byte::<A>(input[1], 1)?;
2051 if v1 & 0b0000_1111 != 0 {
2052 return Err(DecodeError::InvalidPadding { index: 1 });
2053 }
2054 Ok(())
2055 }
2056 3 => {
2057 decode_byte::<A>(input[0], 0)?;
2058 decode_byte::<A>(input[1], 1)?;
2059 let v2 = decode_byte::<A>(input[2], 2)?;
2060 if v2 & 0b0000_0011 != 0 {
2061 return Err(DecodeError::InvalidPadding { index: 2 });
2062 }
2063 Ok(())
2064 }
2065 _ => Err(DecodeError::InvalidLength),
2066 }
2067}
2068
2069fn decode_tail_unpadded<A: Alphabet>(
2070 input: &[u8],
2071 output: &mut [u8],
2072) -> Result<usize, DecodeError> {
2073 match input.len() {
2074 0 => Ok(0),
2075 2 => {
2076 if output.is_empty() {
2077 return Err(DecodeError::OutputTooSmall {
2078 required: 1,
2079 available: output.len(),
2080 });
2081 }
2082 let v0 = decode_byte::<A>(input[0], 0)?;
2083 let v1 = decode_byte::<A>(input[1], 1)?;
2084 if v1 & 0b0000_1111 != 0 {
2085 return Err(DecodeError::InvalidPadding { index: 1 });
2086 }
2087 output[0] = (v0 << 2) | (v1 >> 4);
2088 Ok(1)
2089 }
2090 3 => {
2091 if output.len() < 2 {
2092 return Err(DecodeError::OutputTooSmall {
2093 required: 2,
2094 available: output.len(),
2095 });
2096 }
2097 let v0 = decode_byte::<A>(input[0], 0)?;
2098 let v1 = decode_byte::<A>(input[1], 1)?;
2099 let v2 = decode_byte::<A>(input[2], 2)?;
2100 if v2 & 0b0000_0011 != 0 {
2101 return Err(DecodeError::InvalidPadding { index: 2 });
2102 }
2103 output[0] = (v0 << 2) | (v1 >> 4);
2104 output[1] = (v1 << 4) | (v2 >> 2);
2105 Ok(2)
2106 }
2107 _ => Err(DecodeError::InvalidLength),
2108 }
2109}
2110
2111fn decode_byte<A: Alphabet>(byte: u8, index: usize) -> Result<u8, DecodeError> {
2112 A::decode(byte).ok_or(DecodeError::InvalidByte { index, byte })
2113}
2114
2115fn ct_decode_slice<A: Alphabet, const PAD: bool>(
2116 input: &[u8],
2117 output: &mut [u8],
2118) -> Result<usize, DecodeError> {
2119 if input.is_empty() {
2120 return Ok(0);
2121 }
2122
2123 if PAD {
2124 ct_decode_padded::<A>(input, output)
2125 } else {
2126 ct_decode_unpadded::<A>(input, output)
2127 }
2128}
2129
2130fn ct_decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
2131 if !input.len().is_multiple_of(4) {
2132 return Err(DecodeError::InvalidLength);
2133 }
2134
2135 let padding = ct_padding_len(input);
2136 let required = input.len() / 4 * 3 - padding;
2137 if output.len() < required {
2138 return Err(DecodeError::OutputTooSmall {
2139 required,
2140 available: output.len(),
2141 });
2142 }
2143
2144 let mut invalid_byte = 0u8;
2145 let mut invalid_padding = 0u8;
2146 let mut write = 0;
2147 let mut read = 0;
2148
2149 while read < input.len() {
2150 let is_last = read + 4 == input.len();
2151 let b0 = input[read];
2152 let b1 = input[read + 1];
2153 let b2 = input[read + 2];
2154 let b3 = input[read + 3];
2155 let (v0, valid0) = ct_decode_ascii_base64::<A>(b0);
2156 let (v1, valid1) = ct_decode_ascii_base64::<A>(b1);
2157 let (v2, valid2) = ct_decode_ascii_base64::<A>(b2);
2158 let (v3, valid3) = ct_decode_ascii_base64::<A>(b3);
2159
2160 invalid_byte |= u8::from(!valid0);
2161 invalid_byte |= u8::from(!valid1);
2162
2163 if is_last && padding == 2 {
2164 invalid_padding |= u8::from((v1 & 0b0000_1111) != 0);
2165 output[write] = (v0 << 2) | (v1 >> 4);
2166 write += 1;
2167 } else if is_last && padding == 1 {
2168 invalid_byte |= u8::from(!valid2);
2169 invalid_padding |= u8::from(b2 == b'=');
2170 invalid_padding |= u8::from((v2 & 0b0000_0011) != 0);
2171 output[write] = (v0 << 2) | (v1 >> 4);
2172 output[write + 1] = (v1 << 4) | (v2 >> 2);
2173 write += 2;
2174 } else {
2175 invalid_byte |= u8::from(!valid2);
2176 invalid_byte |= u8::from(!valid3);
2177 invalid_padding |= u8::from(b2 == b'=');
2178 invalid_padding |= u8::from(b3 == b'=');
2179 output[write] = (v0 << 2) | (v1 >> 4);
2180 output[write + 1] = (v1 << 4) | (v2 >> 2);
2181 output[write + 2] = (v2 << 6) | v3;
2182 write += 3;
2183 }
2184
2185 read += 4;
2186 }
2187
2188 report_ct_error(invalid_byte, invalid_padding)?;
2189 Ok(write)
2190}
2191
2192fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
2193 if input.len() % 4 == 1 {
2194 return Err(DecodeError::InvalidLength);
2195 }
2196
2197 let required = decoded_capacity(input.len());
2198 if output.len() < required {
2199 return Err(DecodeError::OutputTooSmall {
2200 required,
2201 available: output.len(),
2202 });
2203 }
2204
2205 let mut invalid_byte = 0u8;
2206 let mut invalid_padding = 0u8;
2207 let mut write = 0;
2208 let mut read = 0;
2209
2210 while read + 4 <= input.len() {
2211 let b0 = input[read];
2212 let b1 = input[read + 1];
2213 let b2 = input[read + 2];
2214 let b3 = input[read + 3];
2215 let (v0, valid0) = ct_decode_ascii_base64::<A>(b0);
2216 let (v1, valid1) = ct_decode_ascii_base64::<A>(b1);
2217 let (v2, valid2) = ct_decode_ascii_base64::<A>(b2);
2218 let (v3, valid3) = ct_decode_ascii_base64::<A>(b3);
2219
2220 invalid_byte |= u8::from(!valid0);
2221 invalid_byte |= u8::from(!valid1);
2222 invalid_byte |= u8::from(!valid2);
2223 invalid_byte |= u8::from(!valid3);
2224 invalid_padding |= u8::from(b0 == b'=');
2225 invalid_padding |= u8::from(b1 == b'=');
2226 invalid_padding |= u8::from(b2 == b'=');
2227 invalid_padding |= u8::from(b3 == b'=');
2228
2229 output[write] = (v0 << 2) | (v1 >> 4);
2230 output[write + 1] = (v1 << 4) | (v2 >> 2);
2231 output[write + 2] = (v2 << 6) | v3;
2232 read += 4;
2233 write += 3;
2234 }
2235
2236 match input.len() - read {
2237 0 => {}
2238 2 => {
2239 let b0 = input[read];
2240 let b1 = input[read + 1];
2241 let (v0, valid0) = ct_decode_ascii_base64::<A>(b0);
2242 let (v1, valid1) = ct_decode_ascii_base64::<A>(b1);
2243 invalid_byte |= u8::from(!valid0);
2244 invalid_byte |= u8::from(!valid1);
2245 invalid_padding |= u8::from(b0 == b'=');
2246 invalid_padding |= u8::from(b1 == b'=');
2247 invalid_padding |= u8::from((v1 & 0b0000_1111) != 0);
2248 output[write] = (v0 << 2) | (v1 >> 4);
2249 write += 1;
2250 }
2251 3 => {
2252 let b0 = input[read];
2253 let b1 = input[read + 1];
2254 let b2 = input[read + 2];
2255 let (v0, valid0) = ct_decode_ascii_base64::<A>(b0);
2256 let (v1, valid1) = ct_decode_ascii_base64::<A>(b1);
2257 let (v2, valid2) = ct_decode_ascii_base64::<A>(b2);
2258 invalid_byte |= u8::from(!valid0);
2259 invalid_byte |= u8::from(!valid1);
2260 invalid_byte |= u8::from(!valid2);
2261 invalid_padding |= u8::from(b0 == b'=');
2262 invalid_padding |= u8::from(b1 == b'=');
2263 invalid_padding |= u8::from(b2 == b'=');
2264 invalid_padding |= u8::from((v2 & 0b0000_0011) != 0);
2265 output[write] = (v0 << 2) | (v1 >> 4);
2266 output[write + 1] = (v1 << 4) | (v2 >> 2);
2267 write += 2;
2268 }
2269 _ => return Err(DecodeError::InvalidLength),
2270 }
2271
2272 report_ct_error(invalid_byte, invalid_padding)?;
2273 Ok(write)
2274}
2275
2276#[inline]
2277fn ct_decode_ascii_base64<A: Alphabet>(byte: u8) -> (u8, bool) {
2278 let upper = mask_if(byte.wrapping_sub(b'A') <= b'Z' - b'A');
2279 let lower = mask_if(byte.wrapping_sub(b'a') <= b'z' - b'a');
2280 let digit = mask_if(byte.wrapping_sub(b'0') <= b'9' - b'0');
2281 let value_62 = mask_if(byte == A::ENCODE[62]);
2282 let value_63 = mask_if(byte == A::ENCODE[63]);
2283 let valid = upper | lower | digit | value_62 | value_63;
2284
2285 let decoded = (byte.wrapping_sub(b'A') & upper)
2286 | (byte.wrapping_sub(b'a').wrapping_add(26) & lower)
2287 | (byte.wrapping_sub(b'0').wrapping_add(52) & digit)
2288 | (0x3e & value_62)
2289 | (0x3f & value_63);
2290
2291 (decoded, valid != 0)
2292}
2293
2294fn ct_padding_len(input: &[u8]) -> usize {
2295 let last = input[input.len() - 1];
2296 let before_last = input[input.len() - 2];
2297 usize::from(mask_if(last == b'=') & 1) + usize::from(mask_if(before_last == b'=') & 1)
2298}
2299
2300fn report_ct_error(invalid_byte: u8, invalid_padding: u8) -> Result<(), DecodeError> {
2301 if invalid_padding != 0 {
2302 Err(DecodeError::InvalidPadding { index: 0 })
2303 } else if invalid_byte != 0 {
2304 Err(DecodeError::InvalidByte { index: 0, byte: 0 })
2305 } else {
2306 Ok(())
2307 }
2308}
2309
2310#[cfg(test)]
2311mod tests {
2312 use super::*;
2313
2314 #[test]
2315 fn encodes_standard_vectors() {
2316 let vectors = [
2317 (&b""[..], &b""[..]),
2318 (&b"f"[..], &b"Zg=="[..]),
2319 (&b"fo"[..], &b"Zm8="[..]),
2320 (&b"foo"[..], &b"Zm9v"[..]),
2321 (&b"foob"[..], &b"Zm9vYg=="[..]),
2322 (&b"fooba"[..], &b"Zm9vYmE="[..]),
2323 (&b"foobar"[..], &b"Zm9vYmFy"[..]),
2324 ];
2325 for (input, expected) in vectors {
2326 let mut output = [0u8; 16];
2327 let written = STANDARD.encode_slice(input, &mut output).unwrap();
2328 assert_eq!(&output[..written], expected);
2329 }
2330 }
2331
2332 #[test]
2333 fn decodes_standard_vectors() {
2334 let vectors = [
2335 (&b""[..], &b""[..]),
2336 (&b"Zg=="[..], &b"f"[..]),
2337 (&b"Zm8="[..], &b"fo"[..]),
2338 (&b"Zm9v"[..], &b"foo"[..]),
2339 (&b"Zm9vYg=="[..], &b"foob"[..]),
2340 (&b"Zm9vYmE="[..], &b"fooba"[..]),
2341 (&b"Zm9vYmFy"[..], &b"foobar"[..]),
2342 ];
2343 for (input, expected) in vectors {
2344 let mut output = [0u8; 16];
2345 let written = STANDARD.decode_slice(input, &mut output).unwrap();
2346 assert_eq!(&output[..written], expected);
2347 }
2348 }
2349
2350 #[test]
2351 fn supports_unpadded_url_safe() {
2352 let mut encoded = [0u8; 16];
2353 let written = URL_SAFE_NO_PAD
2354 .encode_slice(b"\xfb\xff", &mut encoded)
2355 .unwrap();
2356 assert_eq!(&encoded[..written], b"-_8");
2357
2358 let mut decoded = [0u8; 2];
2359 let written = URL_SAFE_NO_PAD
2360 .decode_slice(&encoded[..written], &mut decoded)
2361 .unwrap();
2362 assert_eq!(&decoded[..written], b"\xfb\xff");
2363 }
2364
2365 #[test]
2366 fn decodes_in_place() {
2367 let mut buffer = *b"Zm9vYmFy";
2368 let decoded = STANDARD_NO_PAD.decode_in_place(&mut buffer).unwrap();
2369 assert_eq!(decoded, b"foobar");
2370 }
2371
2372 #[test]
2373 fn rejects_non_canonical_padding_bits() {
2374 let mut output = [0u8; 4];
2375 assert_eq!(
2376 STANDARD.decode_slice(b"Zh==", &mut output),
2377 Err(DecodeError::InvalidPadding { index: 1 })
2378 );
2379 assert_eq!(
2380 STANDARD.decode_slice(b"Zm9=", &mut output),
2381 Err(DecodeError::InvalidPadding { index: 2 })
2382 );
2383 }
2384}