1use crate::error::*;
2use crate::{Decoder, Encoder};
3
4struct Base32Impl;
5
6#[derive(Copy, Clone, Debug, Eq, PartialEq)]
7enum Base32Variant {
8 Standard = 1,
9 StandardNoPadding = 3,
10 Hex = 5,
11 HexNoPadding = 7,
12}
13
14enum VariantMask {
15 NoPadding = 2,
16 Hex = 4,
17}
18
19impl Base32Impl {
20 #[inline]
21 fn is_no_padding(variant: Base32Variant) -> bool {
22 (variant as u16 & VariantMask::NoPadding as u16) != 0
23 }
24
25 #[inline]
26 fn is_hex(variant: Base32Variant) -> bool {
27 (variant as u16 & VariantMask::Hex as u16) != 0
28 }
29
30 #[inline]
31 fn _eq(x: u8, y: u8) -> u8 {
32 !(((0u16.wrapping_sub((x as u16) ^ (y as u16))) >> 8) as u8)
33 }
34
35 #[inline]
36 fn _gt(x: u8, y: u8) -> u8 {
37 (((y as u16).wrapping_sub(x as u16)) >> 8) as u8
38 }
39
40 #[inline]
41 fn _ge(x: u8, y: u8) -> u8 {
42 !Self::_gt(y, x)
43 }
44
45 #[inline]
46 fn _lt(x: u8, y: u8) -> u8 {
47 Self::_gt(y, x)
48 }
49
50 #[inline]
51 fn _le(x: u8, y: u8) -> u8 {
52 Self::_ge(y, x)
53 }
54
55 #[inline]
56 fn b32_byte_to_char(x: u8) -> u8 {
57 (Self::_lt(x, 26) & (x.wrapping_add(b'A')))
58 | (Self::_ge(x, 26) & Self::_lt(x, 32) & (x.wrapping_add(b'2'.wrapping_sub(26))))
59 }
60
61 #[inline]
62 fn b32_char_to_byte(c: u8) -> u8 {
63 let x = (Self::_ge(c, b'A') & Self::_le(c, b'Z') & (c.wrapping_sub(b'A')))
64 | (Self::_ge(c, b'2') & Self::_le(c, b'7') & (c.wrapping_sub(b'2').wrapping_add(26)));
65 x | (Self::_eq(x, 0) & (Self::_eq(c, b'A') ^ 0xff))
66 }
67
68 #[inline]
69 fn b32_hex_byte_to_char(x: u8) -> u8 {
70 (Self::_lt(x, 10) & (x.wrapping_add(b'0')))
71 | (Self::_ge(x, 10) & Self::_lt(x, 32) & (x.wrapping_add(b'A'.wrapping_sub(10))))
72 }
73
74 #[inline]
75 fn b32_hex_char_to_byte(c: u8) -> u8 {
76 let x = (Self::_ge(c, b'0') & Self::_le(c, b'9') & (c.wrapping_sub(b'0')))
77 | (Self::_ge(c, b'A') & Self::_le(c, b'V') & (c.wrapping_sub(b'A').wrapping_add(10)));
78 x | (Self::_eq(x, 0) & ((Self::_eq(c, b'0') | Self::_eq(c, b'A')) ^ 0xff))
79 }
80
81 #[inline]
82 #[allow(clippy::manual_div_ceil)]
83 fn encoded_len(bin_len: usize, variant: Base32Variant) -> Result<usize, Error> {
84 let groups = bin_len / 5;
85 let remainder = bin_len - 5 * groups;
86 let mut b32_len = groups.checked_mul(8).ok_or(Error::Overflow)?;
87 if remainder != 0 {
88 let remainder_len = if Self::is_no_padding(variant) {
89 (remainder * 8 + 4) / 5
90 } else {
91 8
92 };
93 b32_len = b32_len.checked_add(remainder_len).ok_or(Error::Overflow)?;
94 }
95 Ok(b32_len)
96 }
97
98 #[allow(clippy::manual_div_ceil)]
99 pub fn encode<'t>(
100 b32: &'t mut [u8],
101 bin: &[u8],
102 variant: Base32Variant,
103 ) -> Result<&'t [u8], Error> {
104 let b32_len = Self::encoded_len(bin.len(), variant)?;
105 let b32_maxlen = b32.len();
106 let mut acc_len = 0usize;
107 let mut b32_pos = 0usize;
108 let mut acc = 0u16;
109
110 if b32_maxlen < b32_len {
111 return Err(Error::Overflow);
112 }
113 if Self::is_hex(variant) {
114 for &v in bin {
115 acc = (acc << 8) + v as u16;
116 acc_len += 8;
117 while acc_len >= 5 {
118 acc_len -= 5;
119 b32[b32_pos] = Self::b32_hex_byte_to_char(((acc >> acc_len) & 0x1f) as u8);
120 b32_pos += 1;
121 }
122 }
123 if acc_len > 0 {
124 b32[b32_pos] = Self::b32_hex_byte_to_char(((acc << (5 - acc_len)) & 0x1f) as u8);
125 b32_pos += 1;
126 }
127 } else {
128 for &v in bin {
129 acc = (acc << 8) + v as u16;
130 acc_len += 8;
131 while acc_len >= 5 {
132 acc_len -= 5;
133 b32[b32_pos] = Self::b32_byte_to_char(((acc >> acc_len) & 0x1f) as u8);
134 b32_pos += 1;
135 }
136 }
137 if acc_len > 0 {
138 b32[b32_pos] = Self::b32_byte_to_char(((acc << (5 - acc_len)) & 0x1f) as u8);
139 b32_pos += 1;
140 }
141 }
142 while b32_pos < b32_len {
143 b32[b32_pos] = b'=';
144 b32_pos += 1
145 }
146 Ok(&b32[..b32_pos])
147 }
148
149 fn skip_padding<'t>(
150 b32: &'t [u8],
151 mut padding_len: usize,
152 ignore: Option<&[u8]>,
153 ) -> Result<&'t [u8], Error> {
154 let b32_len = b32.len();
155 let mut b32_pos = 0usize;
156 while padding_len > 0 {
157 if b32_pos >= b32_len {
158 return Err(Error::InvalidInput);
159 }
160 let c = b32[b32_pos];
161 if c == b'=' {
162 padding_len -= 1
163 } else {
164 match ignore {
165 Some(ignore) if ignore.contains(&c) => {}
166 _ => return Err(Error::InvalidInput),
167 }
168 }
169 b32_pos += 1
170 }
171 Ok(&b32[b32_pos..])
172 }
173
174 pub fn decode<'t>(
175 bin: &'t mut [u8],
176 b32: &[u8],
177 ignore: Option<&[u8]>,
178 variant: Base32Variant,
179 ) -> Result<&'t [u8], Error> {
180 let bin_maxlen = bin.len();
181 let is_hex = Self::is_hex(variant);
182 let is_no_padding = Self::is_no_padding(variant);
183 let mut acc = 0u16;
184 let mut acc_len = 0usize;
185 let mut bin_pos = 0usize;
186 let mut premature_end = None;
187 for (b32_pos, &c) in b32.iter().enumerate() {
188 let d = if is_hex {
189 Self::b32_hex_char_to_byte(c)
190 } else {
191 Self::b32_char_to_byte(c)
192 };
193 if d == 0xff {
194 match ignore {
195 Some(ignore) if ignore.contains(&c) => continue,
196 _ => {
197 premature_end = Some(b32_pos);
198 break;
199 }
200 }
201 }
202 acc = (acc << 5) + d as u16;
203 acc_len += 5;
204 if acc_len >= 8 {
205 acc_len -= 8;
206 if bin_pos >= bin_maxlen {
207 return Err(Error::Overflow);
208 }
209 bin[bin_pos] = (acc >> acc_len) as u8;
210 bin_pos += 1;
211 }
212 }
213 if acc_len >= 5 || (acc & ((1u16 << acc_len).wrapping_sub(1))) != 0 {
214 return Err(Error::InvalidInput);
215 }
216 let padding_len = [0, 3, 6, 1, 4][acc_len];
217 if let Some(premature_end) = premature_end {
218 let remaining = if !is_no_padding {
219 Self::skip_padding(&b32[premature_end..], padding_len, ignore)?
220 } else {
221 &b32[premature_end..]
222 };
223 match ignore {
224 None => {
225 if !remaining.is_empty() {
226 return Err(Error::InvalidInput);
227 }
228 }
229 Some(ignore) => {
230 for &c in remaining {
231 if !ignore.contains(&c) {
232 return Err(Error::InvalidInput);
233 }
234 }
235 }
236 }
237 } else if !is_no_padding && padding_len != 0 {
238 return Err(Error::InvalidInput);
239 }
240 Ok(&bin[..bin_pos])
241 }
242}
243
244pub struct Base32;
273
274pub struct Base32NoPadding;
296
297pub struct Base32Hex;
327
328pub struct Base32HexNoPadding;
351
352impl Encoder for Base32 {
353 #[inline]
354 fn encoded_len(bin_len: usize) -> Result<usize, Error> {
355 Base32Impl::encoded_len(bin_len, Base32Variant::Standard)
356 }
357
358 #[inline]
359 fn encode<IN: AsRef<[u8]>>(b32: &mut [u8], bin: IN) -> Result<&[u8], Error> {
360 Base32Impl::encode(b32, bin.as_ref(), Base32Variant::Standard)
361 }
362}
363
364impl Decoder for Base32 {
365 #[inline]
366 fn decode<'t, IN: AsRef<[u8]>>(
367 bin: &'t mut [u8],
368 b32: IN,
369 ignore: Option<&[u8]>,
370 ) -> Result<&'t [u8], Error> {
371 Base32Impl::decode(bin, b32.as_ref(), ignore, Base32Variant::Standard)
372 }
373}
374
375impl Encoder for Base32NoPadding {
376 #[inline]
377 fn encoded_len(bin_len: usize) -> Result<usize, Error> {
378 Base32Impl::encoded_len(bin_len, Base32Variant::StandardNoPadding)
379 }
380
381 #[inline]
382 fn encode<IN: AsRef<[u8]>>(b32: &mut [u8], bin: IN) -> Result<&[u8], Error> {
383 Base32Impl::encode(b32, bin.as_ref(), Base32Variant::StandardNoPadding)
384 }
385}
386
387impl Decoder for Base32NoPadding {
388 #[inline]
389 fn decode<'t, IN: AsRef<[u8]>>(
390 bin: &'t mut [u8],
391 b32: IN,
392 ignore: Option<&[u8]>,
393 ) -> Result<&'t [u8], Error> {
394 Base32Impl::decode(bin, b32.as_ref(), ignore, Base32Variant::StandardNoPadding)
395 }
396}
397
398impl Encoder for Base32Hex {
399 #[inline]
400 fn encoded_len(bin_len: usize) -> Result<usize, Error> {
401 Base32Impl::encoded_len(bin_len, Base32Variant::Hex)
402 }
403
404 #[inline]
405 fn encode<IN: AsRef<[u8]>>(b32: &mut [u8], bin: IN) -> Result<&[u8], Error> {
406 Base32Impl::encode(b32, bin.as_ref(), Base32Variant::Hex)
407 }
408}
409
410impl Decoder for Base32Hex {
411 #[inline]
412 fn decode<'t, IN: AsRef<[u8]>>(
413 bin: &'t mut [u8],
414 b32: IN,
415 ignore: Option<&[u8]>,
416 ) -> Result<&'t [u8], Error> {
417 Base32Impl::decode(bin, b32.as_ref(), ignore, Base32Variant::Hex)
418 }
419}
420
421impl Encoder for Base32HexNoPadding {
422 #[inline]
423 fn encoded_len(bin_len: usize) -> Result<usize, Error> {
424 Base32Impl::encoded_len(bin_len, Base32Variant::HexNoPadding)
425 }
426
427 #[inline]
428 fn encode<IN: AsRef<[u8]>>(b32: &mut [u8], bin: IN) -> Result<&[u8], Error> {
429 Base32Impl::encode(b32, bin.as_ref(), Base32Variant::HexNoPadding)
430 }
431}
432
433impl Decoder for Base32HexNoPadding {
434 #[inline]
435 fn decode<'t, IN: AsRef<[u8]>>(
436 bin: &'t mut [u8],
437 b32: IN,
438 ignore: Option<&[u8]>,
439 ) -> Result<&'t [u8], Error> {
440 Base32Impl::decode(bin, b32.as_ref(), ignore, Base32Variant::HexNoPadding)
441 }
442}
443
444#[cfg(feature = "std")]
445#[test]
446fn test_base32() {
447 let test_vectors: &[(&[u8], &str)] = &[
448 (b"", ""),
449 (b"f", "MY======"),
450 (b"fo", "MZXQ===="),
451 (b"foo", "MZXW6==="),
452 (b"foob", "MZXW6YQ="),
453 (b"fooba", "MZXW6YTB"),
454 (b"foobar", "MZXW6YTBOI======"),
455 ];
456 for &(bin, expected) in test_vectors {
457 let b32 = Base32::encode_to_string(bin).unwrap();
458 assert_eq!(b32, expected);
459 let decoded = Base32::decode_to_vec(&b32, None).unwrap();
460 assert_eq!(decoded, bin);
461 }
462}
463
464#[cfg(feature = "std")]
465#[test]
466fn test_base32_no_padding() {
467 let test_vectors: &[(&[u8], &str)] = &[
468 (b"", ""),
469 (b"f", "MY"),
470 (b"fo", "MZXQ"),
471 (b"foo", "MZXW6"),
472 (b"foob", "MZXW6YQ"),
473 (b"fooba", "MZXW6YTB"),
474 (b"foobar", "MZXW6YTBOI"),
475 ];
476 for &(bin, expected) in test_vectors {
477 let b32 = Base32NoPadding::encode_to_string(bin).unwrap();
478 assert_eq!(b32, expected);
479 let decoded = Base32NoPadding::decode_to_vec(&b32, None).unwrap();
480 assert_eq!(decoded, bin);
481 }
482}
483
484#[cfg(feature = "std")]
485#[test]
486fn test_base32_hex() {
487 let test_vectors: &[(&[u8], &str)] = &[
488 (b"", ""),
489 (b"f", "CO======"),
490 (b"fo", "CPNG===="),
491 (b"foo", "CPNMU==="),
492 (b"foob", "CPNMUOG="),
493 (b"fooba", "CPNMUOJ1"),
494 (b"foobar", "CPNMUOJ1E8======"),
495 ];
496 for &(bin, expected) in test_vectors {
497 let b32 = Base32Hex::encode_to_string(bin).unwrap();
498 assert_eq!(b32, expected);
499 let decoded = Base32Hex::decode_to_vec(&b32, None).unwrap();
500 assert_eq!(decoded, bin);
501 }
502}
503
504#[cfg(feature = "std")]
505#[test]
506fn test_base32_hex_no_padding() {
507 let test_vectors: &[(&[u8], &str)] = &[
508 (b"", ""),
509 (b"f", "CO"),
510 (b"fo", "CPNG"),
511 (b"foo", "CPNMU"),
512 (b"foob", "CPNMUOG"),
513 (b"fooba", "CPNMUOJ1"),
514 (b"foobar", "CPNMUOJ1E8"),
515 ];
516 for &(bin, expected) in test_vectors {
517 let b32 = Base32HexNoPadding::encode_to_string(bin).unwrap();
518 assert_eq!(b32, expected);
519 let decoded = Base32HexNoPadding::decode_to_vec(&b32, None).unwrap();
520 assert_eq!(decoded, bin);
521 }
522}
523
524#[test]
525fn test_base32_no_std() {
526 let bin = [1u8, 5, 11, 15, 19, 131, 122];
527 let mut b32 = [0u8; 17];
528 let b32 = Base32::encode(&mut b32, bin).unwrap();
529 let expected = b"AECQWDYTQN5A====";
530 assert_eq!(b32, expected);
531 let mut bin2 = [0u8; 7];
532 let bin2 = Base32::decode(&mut bin2, b32, None).unwrap();
533 assert_eq!(bin, bin2);
534}
535
536#[test]
537fn test_base32_encoded_len() {
538 let test_vectors: &[(usize, usize, usize)] = &[
539 (0, 0, 0),
540 (1, 8, 2),
541 (2, 8, 4),
542 (3, 8, 5),
543 (4, 8, 7),
544 (5, 8, 8),
545 (6, 16, 10),
546 ];
547 for &(bin_len, padded_len, unpadded_len) in test_vectors {
548 assert_eq!(Base32::encoded_len(bin_len), Ok(padded_len));
549 assert_eq!(Base32NoPadding::encoded_len(bin_len), Ok(unpadded_len));
550 assert_eq!(Base32Hex::encoded_len(bin_len), Ok(padded_len));
551 assert_eq!(Base32HexNoPadding::encoded_len(bin_len), Ok(unpadded_len));
552 }
553}
554
555#[test]
556fn test_base32_encoded_len_overflow() {
557 let mult_overflow_bin_len = (usize::MAX / 8 + 1).checked_mul(5).unwrap();
558 assert_eq!(
559 Base32::encoded_len(mult_overflow_bin_len),
560 Err(Error::Overflow)
561 );
562 assert_eq!(
563 Base32NoPadding::encoded_len(mult_overflow_bin_len),
564 Err(Error::Overflow)
565 );
566 assert_eq!(
567 Base32Hex::encoded_len(mult_overflow_bin_len),
568 Err(Error::Overflow)
569 );
570 assert_eq!(
571 Base32HexNoPadding::encoded_len(mult_overflow_bin_len),
572 Err(Error::Overflow)
573 );
574
575 let add_overflow_bin_len = (usize::MAX / 8).checked_mul(5).unwrap() + 1;
576 assert_eq!(
577 Base32::encoded_len(add_overflow_bin_len),
578 Err(Error::Overflow)
579 );
580 assert_eq!(
581 Base32Hex::encoded_len(add_overflow_bin_len),
582 Err(Error::Overflow)
583 );
584}
585
586#[cfg(feature = "std")]
587#[test]
588fn test_base32_missing_padding() {
589 let missing_padding = "MY";
590 assert!(Base32::decode_to_vec(missing_padding, None).is_err());
591 assert!(Base32NoPadding::decode_to_vec(missing_padding, None).is_ok());
592 let missing_padding = "MZXQ";
593 assert!(Base32::decode_to_vec(missing_padding, None).is_err());
594 assert!(Base32NoPadding::decode_to_vec(missing_padding, None).is_ok());
595}
596
597#[cfg(feature = "std")]
598#[test]
599fn test_base32_invalid_padding() {
600 let valid_padding = "MY======";
601 assert_eq!(Base32::decode_to_vec(valid_padding, None), Ok(vec![b'f']));
602 let invalid_padding = "MY=====";
603 assert_eq!(
604 Base32::decode_to_vec(invalid_padding, None),
605 Err(Error::InvalidInput)
606 );
607 let invalid_padding = "MY=";
608 assert_eq!(
609 Base32::decode_to_vec(invalid_padding, None),
610 Err(Error::InvalidInput)
611 );
612}
613
614#[cfg(feature = "std")]
615#[test]
616fn test_base32_non_canonical() {
617 assert!(Base32::decode_to_vec("MZ======", None).is_err());
618 assert!(Base32NoPadding::decode_to_vec("MZ", None).is_err());
619}
620
621#[cfg(feature = "std")]
622#[test]
623fn test_base32_no_padding_rejects_padding() {
624 assert!(Base32NoPadding::decode_to_vec("MY======", None).is_err());
625 assert!(Base32NoPadding::decode_to_vec("MZXQ====", None).is_err());
626}
627
628#[cfg(feature = "std")]
629#[test]
630fn test_base32_hex_rejects_lowercase() {
631 assert!(Base32Hex::decode_to_vec("cpnmuoj1e8======", None).is_err());
632 assert!(Base32HexNoPadding::decode_to_vec("cpnmuoj1e8", None).is_err());
633}