1const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
10
11pub fn h_p(input: &[u8]) -> String {
12 if input.is_empty() {
13 return String::new();
14 }
15 let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
16 let mut i = 0;
17 while i + 3 <= input.len() {
18 let o =
19 (u32::from(input[i]) << 16) | (u32::from(input[i + 1]) << 8) | u32::from(input[i + 2]);
20 out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
21 out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
22 out.push(ALPHABET[((o >> 6) & 63) as usize] as char);
23 out.push(ALPHABET[(o & 63) as usize] as char);
24 i += 3;
25 }
26 let rem = input.len() - i;
27 if rem == 1 {
28 let o = u32::from(input[i]) << 16;
29 out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
30 out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
31 out.push('=');
32 out.push('=');
33 } else if rem == 2 {
34 let o = (u32::from(input[i]) << 16) | (u32::from(input[i + 1]) << 8);
35 out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
36 out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
37 out.push(ALPHABET[((o >> 6) & 63) as usize] as char);
38 out.push('=');
39 }
40 out
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn rfc4648_vectors() {
49 assert_eq!(h_p(b""), "");
50 assert_eq!(h_p(b"f"), "Zg==");
51 assert_eq!(h_p(b"fo"), "Zm8=");
52 assert_eq!(h_p(b"foo"), "Zm9v");
53 assert_eq!(h_p(b"foob"), "Zm9vYg==");
54 assert_eq!(h_p(b"fooba"), "Zm9vYmE=");
55 assert_eq!(h_p(b"foobar"), "Zm9vYmFy");
56 }
57}