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