rust_auth_utils/
base32.rs1use std::collections::HashMap;
4
5fn get_alphabet(hex: bool) -> &'static str {
9 if hex {
10 "0123456789ABCDEFGHIJKLMNOPQRSTUV"
11 } else {
12 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
13 }
14}
15
16fn create_decode_map(alphabet: &str) -> HashMap<char, u8> {
20 alphabet
21 .chars()
22 .enumerate()
23 .map(|(i, c)| (c, i as u8))
24 .collect()
25}
26
27fn base32_encode(data: &[u8], alphabet: &str, padding: bool) -> String {
31 if data.is_empty() {
32 return String::new();
33 }
34
35 let mut result = String::with_capacity((data.len() * 8 + 4) / 5);
36 let mut buffer = 0u16;
37 let mut bits_left = 0;
38
39 for &byte in data {
40 buffer = (buffer << 8) | (byte as u16);
41 bits_left += 8;
42
43 while bits_left >= 5 {
44 let val = (buffer >> (bits_left - 5)) & 0x1F;
45 result.push(alphabet.chars().nth(val as usize).unwrap());
46 bits_left -= 5;
47 }
48 }
49
50 if bits_left > 0 {
51 buffer <<= 5 - bits_left;
52 let val = (buffer & 0x1F) as usize;
53 result.push(alphabet.chars().nth(val).unwrap());
54 }
55
56 if padding {
57 while (result.len() % 8) != 0 {
58 result.push('=');
59 }
60 }
61
62 result
63}
64
65fn base32_decode(data: &str, alphabet: &str) -> Result<Vec<u8>, String> {
69 let decode_map = create_decode_map(alphabet);
70 let mut result = Vec::new();
71 let mut buffer = 0u16;
72 let mut bits_left = 0;
73
74 for c in data.chars().filter(|&c| c != '=') {
75 let val = decode_map
76 .get(&c.to_ascii_uppercase())
77 .ok_or_else(|| format!("Invalid Base32 character: {}", c))?;
78
79 buffer = (buffer << 5) | (*val as u16);
80 bits_left += 5;
81
82 if bits_left >= 8 {
83 result.push((buffer >> (bits_left - 8)) as u8);
84 bits_left -= 8;
85 }
86 }
87
88 if bits_left > 0 && bits_left >= 5 {
89 buffer <<= 8 - bits_left;
90 result.push((buffer >> (bits_left - 8)) as u8);
91 }
92
93 Ok(result)
94}
95
96#[derive(Default)]
97pub struct Base32;
98
99impl Base32 {
100 pub fn encode(data: &[u8], padding: Option<bool>) -> String {
104 let alphabet = get_alphabet(false);
105 base32_encode(data, alphabet, padding.unwrap_or(true))
106 }
107
108 pub fn decode(data: &str) -> Result<Vec<u8>, String> {
112 let alphabet = get_alphabet(false);
113 base32_decode(data, alphabet)
114 }
115}
116
117#[derive(Default)]
118pub struct Base32Hex;
119
120impl Base32Hex {
121 pub fn encode(data: &[u8], padding: Option<bool>) -> String {
125 let alphabet = get_alphabet(true);
126 base32_encode(data, alphabet, padding.unwrap_or(true))
127 }
128
129 pub fn decode(data: &str) -> Result<Vec<u8>, String> {
133 let alphabet = get_alphabet(true);
134 base32_decode(data, alphabet)
135 }
136}