base_encoding/decode/
base64url.rs

1// Copyright 2017 ThetaSinner
2//
3// This file is part of base-encoding.
4//
5// base-encoding is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// base-encoding is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with base-encoding. If not, see <http://www.gnu.org/licenses/>.
17
18const BASE_64_URL_ALPHABET: [u8; 64] = [
19    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', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z',
20    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', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
21    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
22    b'-', b'_'
23];
24
25const BASE_64_URL_MASK: u8 = 0x3F;
26
27pub fn base64url(input: &str) -> Vec<u8> {
28    let padded_input = match input.len() % 4 {
29        0 => {
30            String::from(input)
31        },
32        1 => {
33            panic!("bad input");
34        },
35        2 => {
36            let mut s = String::from(input);
37            s.push_str("==");
38            s
39        },
40        3 => {
41            let mut s = String::from(input);
42            s.push_str("=");
43            s
44        },
45        _ => {
46            unreachable!("mod 4");
47        }
48    };
49
50    padded_input.as_bytes().chunks(4).map(|x| {
51        if x[2] == b'=' && x[3] == b'=' {
52            let buf: u32 = 
53                (((lookup(x[0]).unwrap() & BASE_64_URL_MASK) as u32) << 18) +
54                (((lookup(x[1]).unwrap() & BASE_64_URL_MASK) as u32) << 12);
55
56            vec![
57                (buf >> 16) as u8
58            ]
59        }
60        else if x[3] == b'=' {
61            let buf: u32 = 
62                (((lookup(x[0]).unwrap() & BASE_64_URL_MASK) as u32) << 18) +
63                (((lookup(x[1]).unwrap() & BASE_64_URL_MASK) as u32) << 12) +
64                (((lookup(x[2]).unwrap() & BASE_64_URL_MASK) as u32) << 6);
65
66            vec![
67                (buf >> 16) as u8,
68                (buf >> 8) as u8
69            ]
70        }
71        else {
72            let buf: u32 = 
73                (((lookup(x[0]).unwrap() & BASE_64_URL_MASK) as u32) << 18) +
74                (((lookup(x[1]).unwrap() & BASE_64_URL_MASK) as u32) << 12) +
75                (((lookup(x[2]).unwrap() & BASE_64_URL_MASK) as u32) << 6) +
76                ((lookup(x[3]).unwrap() & BASE_64_URL_MASK) as u32);
77
78            vec![
79                (buf >> 16) as u8,
80                (buf >> 8) as u8,
81                buf as u8
82            ]
83        }
84    }).fold(Vec::new(), |mut acc, x| {
85        acc.extend(x);
86        acc
87    })
88}
89
90fn lookup(b: u8) -> Result<u8, ()> {
91    for (i, byte) in BASE_64_URL_ALPHABET.iter().enumerate() {
92        if byte == &b {
93            return Ok(i as u8)
94        }
95    }
96
97    Err(())
98}