1use super::headers::Writer;
8use std::slice::Iter;
9
10pub(crate) static BASE32_ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
11pub static BASE32_INVERSE: [u8; 256] = [
12 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
13 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
14 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 255, 255,
15 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
16 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
17 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255,
18 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
19 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
20 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
21 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
22 255, 255, 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, 255, 255,
24 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
25];
26
27pub struct Base32Writer {
28 last_byte: u8,
29 pos: usize,
30 result: String,
31}
32
33impl Base32Writer {
34 pub fn encode(bytes: &[u8]) -> String {
35 let mut w = Base32Writer::with_capacity(bytes.len());
36 w.write(bytes);
37 w.finalize()
38 }
39
40 pub fn with_capacity(capacity: usize) -> Self {
41 Base32Writer {
42 result: String::with_capacity(capacity.div_ceil(4) * 5),
43 last_byte: 0,
44 pos: 0,
45 }
46 }
47
48 pub fn push_byte(&mut self, byte: u8, is_remainder: bool) {
49 let (ch1, ch2) = match self.pos % 5 {
50 0 => ((byte & 0xF8) >> 3, u8::MAX),
51 1 => (
52 (((self.last_byte & 0x07) << 2) | ((byte & 0xC0) >> 6)),
53 ((byte & 0x3E) >> 1),
54 ),
55 2 => (
56 (((self.last_byte & 0x01) << 4) | ((byte & 0xF0) >> 4)),
57 u8::MAX,
58 ),
59 3 => (
60 (((self.last_byte & 0x0F) << 1) | (byte >> 7)),
61 ((byte & 0x7C) >> 2),
62 ),
63 4 => (
64 (((self.last_byte & 0x03) << 3) | ((byte & 0xE0) >> 5)),
65 (byte & 0x1F),
66 ),
67 _ => unreachable!(),
68 };
69
70 self.result.push(char::from(BASE32_ALPHABET[ch1 as usize]));
71 if !is_remainder {
72 if ch2 != u8::MAX {
73 self.result.push(char::from(BASE32_ALPHABET[ch2 as usize]));
74 }
75 self.last_byte = byte;
76 self.pos += 1;
77 }
78 }
79
80 pub fn finalize(mut self) -> String {
81 if !self.pos.is_multiple_of(5) {
82 self.push_byte(0, true);
83 }
84
85 self.result
86 }
87}
88
89impl Writer for Base32Writer {
90 fn write(&mut self, buf: &[u8]) {
91 for &byte in buf {
92 self.push_byte(byte, false);
93 }
94 }
95}
96
97#[derive(Debug)]
98pub struct Base32Reader<'x> {
99 bytes: Iter<'x, u8>,
100 last_byte: u8,
101 pos: usize,
102}
103
104impl<'x> Base32Reader<'x> {
105 pub fn new(bytes: &'x [u8]) -> Self {
106 Base32Reader {
107 bytes: bytes.iter(),
108 pos: 0,
109 last_byte: 0,
110 }
111 }
112
113 #[inline(always)]
114 fn map_byte(&mut self) -> Option<u8> {
115 match self.bytes.next() {
116 Some(&byte) => match BASE32_INVERSE[byte as usize] {
117 byte if byte != u8::MAX => {
118 self.last_byte = byte;
119 Some(byte)
120 }
121 _ => None,
122 },
123 _ => None,
124 }
125 }
126}
127
128impl Iterator for Base32Reader<'_> {
129 type Item = u8;
130 fn next(&mut self) -> Option<Self::Item> {
131 let pos = self.pos % 5;
132 let last_byte = self.last_byte;
133 let byte = self.map_byte()?;
134 self.pos += 1;
135
136 match pos {
137 0 => ((byte << 3) | (self.map_byte().unwrap_or(0) >> 2)).into(),
138 1 => ((last_byte << 6) | (byte << 1) | (self.map_byte().unwrap_or(0) >> 4)).into(),
139 2 => ((last_byte << 4) | (byte >> 1)).into(),
140 3 => ((last_byte << 7) | (byte << 2) | (self.map_byte().unwrap_or(0) >> 3)).into(),
141 4 => ((last_byte << 5) | byte).into(),
142 _ => None,
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use crate::common::{
150 base32::{Base32Reader, Base32Writer},
151 crypto::{HashContext, HashImpl, Sha1},
152 headers::Writer,
153 };
154
155 #[test]
156 fn base32_hash() {
157 for (test, expected_result) in [
158 ("one.example.net", "QSP4I4D24CRHOPDZ3O3ZIU2KSGS3X6Z6"),
159 ("two.example.net", "ZTZGRRV3F45A4U6HLDKBF3ZCOW4V2AJX"),
160 ] {
161 let mut writer = Base32Writer::with_capacity(10);
163 let mut hash = Sha1::hasher();
164 hash.write(test.as_bytes());
165 let hash = hash.complete();
166 writer.write(hash.as_ref());
167 assert_eq!(writer.finalize(), expected_result);
168
169 let mut original = Vec::new();
171 for byte in Base32Reader::new(expected_result.as_bytes()) {
172 original.push(byte);
173 }
174 assert_eq!(original, hash.as_ref());
175 }
176 }
177}