Skip to main content

binarytext/
base32.rs

1use crate::binarytext::BinaryText;
2use crate::error::BinTxtError;
3
4/// Base32 implementation as described in RFC 4648 / Section 6.
5#[derive(Clone, Debug)]
6pub struct Base32 {
7    name: String,
8    lut_enc: [u8; 32],
9    lut_dec: [u8; 128],
10}
11
12impl Base32 {
13    /// Returns the Base32 encoder as described in RFC 4648 / Section 6.
14    pub fn new() -> Self {
15        let name = "Base32".to_string();
16        let lut_enc = [
17            b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N',
18            b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'2', b'3',
19            b'4', b'5', b'6', b'7',
20        ];
21        let lut_dec = [
22            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
23            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
24            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26, 27,
25            28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8,
26            9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255,
27            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
28            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
29        ];
30        Self {
31            name,
32            lut_enc,
33            lut_dec,
34        }
35    }
36
37    /// Returns the Base32 variant Base32Hex as described in RFC 4648 / Section 7.
38    pub fn base32hex() -> Self {
39        let name = "Base32Hex".to_string();
40        let lut_enc = [
41            b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
42            b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R',
43            b'S', b'T', b'U', b'V',
44        ];
45        let lut_dec = [
46            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
47            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
48            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5,
49            6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
50            20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255,
51            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
52            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
53        ];
54        Self {
55            name,
56            lut_enc,
57            lut_dec,
58        }
59    }
60}
61
62impl BinaryText for Base32 {
63    fn base(&self) -> usize {
64        32
65    }
66
67    fn name(&self) -> &str {
68        self.name.as_str()
69    }
70
71    fn n_bytes_encode(&self) -> usize {
72        5
73    }
74
75    fn n_bytes_decode(&self) -> usize {
76        8
77    }
78
79    fn encode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
80        if byte >= 32 {
81            let msg = format!("Byte {byte} exceeds maximum {}", 32);
82            return Err(BinTxtError::EncodingErr(msg));
83        }
84        Ok(self.lut_enc[byte as usize])
85    }
86
87    fn encode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
88        let encode_block = |bytes_in: &[u8], bytes_out: &mut [u8]| -> Result<(), BinTxtError> {
89            // Loop unrolled
90            let pos = bytes_in[0] >> 3;
91            bytes_out[0] = self.encode_byte(pos)?;
92            let pos = ((bytes_in[0] & 0b111) << 2) | (bytes_in[1] >> 6);
93            bytes_out[1] = self.encode_byte(pos)?;
94            let pos = (bytes_in[1] & 0b111110) >> 1;
95            bytes_out[2] = self.encode_byte(pos)?;
96            let pos = ((bytes_in[1] & 0b1) << 4) | (bytes_in[2] >> 4);
97            bytes_out[3] = self.encode_byte(pos)?;
98            let pos = ((bytes_in[2] & 0b1111) << 1) | (bytes_in[3] >> 7);
99            bytes_out[4] = self.encode_byte(pos)?;
100            let pos = (bytes_in[3] & 0b1111100) >> 2;
101            bytes_out[5] = self.encode_byte(pos)?;
102            let pos = ((bytes_in[3] & 0b11) << 3) | (bytes_in[4] >> 5);
103            bytes_out[6] = self.encode_byte(pos)?;
104            let pos = bytes_in[4] & 0b11111;
105            bytes_out[7] = self.encode_byte(pos)?;
106            Ok(())
107        };
108        res.clear();
109        // Five bytes -> 40 bits
110        let iter = input.chunks_exact(5);
111        let bytes_rem = iter.remainder();
112        let mut bytes_enc = [0u8; 8];
113        for bytes in iter {
114            encode_block(&bytes, &mut bytes_enc)?;
115            res.extend(&bytes_enc);
116        }
117        // Handle the remaining bytes
118        if bytes_rem.len() > 0 {
119            let mut bytes = [0u8; 5];
120            for i in 0..bytes_rem.len() {
121                bytes[i] = bytes_rem[i];
122            }
123            encode_block(&bytes, &mut bytes_enc)?;
124            // Padding
125            let n_bytes_enc = (bytes_rem.len() * 8) / 5 + 1;
126            for i in n_bytes_enc..8 {
127                bytes_enc[i] = b'=';
128            }
129            res.extend(&bytes_enc);
130        }
131        Ok(())
132    }
133
134    fn decode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
135        let b = if byte < 128 {
136            self.lut_dec[byte as usize]
137        } else {
138            255
139        };
140        if b < 255 {
141            Ok(b)
142        } else {
143            let errmsg = format!("Invalid byte \"{}\" in Base32 string", byte);
144            Err(BinTxtError::DecodingErr(errmsg))
145        }
146    }
147
148    fn decode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
149        res.clear();
150        if input.len() == 0 {
151            return Ok(());
152        }
153        // Function for decoding a block of eight bytes into five bytes
154        let decode_block = |bytes_in: &[u8], bytes_out: &mut [u8]| -> Result<(), BinTxtError> {
155            // Loop unrolled
156            let dec0 = self.decode_byte(bytes_in[0])?;
157            let dec1 = self.decode_byte(bytes_in[1])?;
158            let dec2 = self.decode_byte(bytes_in[2])?;
159            let dec3 = self.decode_byte(bytes_in[3])?;
160            let dec4 = self.decode_byte(bytes_in[4])?;
161            let dec5 = self.decode_byte(bytes_in[5])?;
162            let dec6 = self.decode_byte(bytes_in[6])?;
163            let dec7 = self.decode_byte(bytes_in[7])?;
164            bytes_out[0] = (dec0 << 3) | (dec1 >> 2);
165            bytes_out[1] = (dec1 << 6) | (dec2 << 1) | (dec3 >> 4);
166            bytes_out[2] = (dec3 << 4) | (dec4 >> 1);
167            bytes_out[3] = (dec4 << 7) | (dec5 << 2) | (dec6 >> 3);
168            bytes_out[4] = (dec6 << 5) | dec7;
169            Ok(())
170        };
171        // Get the last position before the remainder
172        let rem = input.len() % 8;
173        let pos_last = if rem == 0 {
174            input.len() - 8
175        } else {
176            input.len() - rem
177        };
178        let mut bytes_dec = [0u8; 5];
179        // Decode everything except the remainder bytes
180        // This way we don't have to worry about padding here
181        for bytes in input[0..pos_last].chunks_exact(8) {
182            decode_block(&bytes, &mut bytes_dec)?;
183            res.extend(&bytes_dec);
184        }
185        // Handle the last chunk of bytes with padding
186        let bytes_rem = &input[pos_last..];
187        // Save the position of the first padding character, if it exists
188        let pos_padding = bytes_rem.iter().position(|&x| x == b'=');
189        // 'A' decodes to zero
190        let bytes = {
191            let mut ret = bytes_rem
192                .iter()
193                .cloned()
194                .map(|x| if x == b'=' { b'A' } else { x })
195                .collect::<Vec<u8>>();
196            ret.resize(8, b'A');
197            ret
198        };
199        decode_block(&bytes, &mut bytes_dec)?;
200        match pos_padding {
201            Some(2) => {
202                res.extend(&bytes_dec[0..1]);
203            }
204            Some(3) => {
205                res.extend(&bytes_dec[0..2]);
206            }
207            Some(4) => {
208                res.extend(&bytes_dec[0..2]);
209            }
210            Some(5) => {
211                res.extend(&bytes_dec[0..3]);
212            }
213            Some(6) => {
214                res.extend(&bytes_dec[0..3]);
215            }
216            Some(7) => {
217                res.extend(&bytes_dec[0..4]);
218            }
219            _ => {
220                res.extend(&bytes_dec);
221            }
222        }
223        Ok(())
224    }
225
226    fn is_decodable(&self, input: &str) -> bool {
227        let rem = input.len() % 8;
228        let pos_last = if rem == 0 {
229            input.len() - 8
230        } else {
231            input.len() - rem
232        };
233        for &byte in input[0..pos_last].as_bytes() {
234            if self.decode_byte(byte).is_err() {
235                return false;
236            }
237        }
238        // In the last chunk padding character "=" is valid
239        for &byte in input[pos_last..].as_bytes() {
240            if byte != b'=' && self.decode_byte(byte).is_err() {
241                return false;
242            }
243        }
244        true
245    }
246}