minisign_verify/
base64.rs1#![forbid(unsafe_code)]
2
3use core::fmt::{self, Display};
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
6pub enum Error {
7 Overflow,
9 InvalidInput,
11}
12
13impl std::error::Error for Error {}
14
15impl Display for Error {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 match self {
18 Error::Overflow => write!(f, "Overflow"),
19 Error::InvalidInput => write!(f, "Invalid input"),
20 }
21 }
22}
23
24pub trait Decoder {
25 fn decode<IN: AsRef<[u8]>>(bin: &mut [u8], encoded: IN) -> Result<&[u8], Error>;
29
30 fn decode_to_vec<IN: AsRef<[u8]>>(encoded: IN) -> Result<Vec<u8>, Error> {
32 let mut bin = vec![0u8; encoded.as_ref().len()];
33 let bin_len = Self::decode(&mut bin, encoded)?.len();
34 bin.truncate(bin_len);
35 Ok(bin)
36 }
37}
38
39struct Base64Impl;
40
41impl Base64Impl {
42 #[inline]
43 fn _eq(x: u8, y: u8) -> u8 {
44 !(((0u16.wrapping_sub((x as u16) ^ (y as u16))) >> 8) as u8)
45 }
46
47 #[inline]
48 fn _gt(x: u8, y: u8) -> u8 {
49 (((y as u16).wrapping_sub(x as u16)) >> 8) as u8
50 }
51
52 #[inline]
53 fn _ge(x: u8, y: u8) -> u8 {
54 !Self::_gt(y, x)
55 }
56
57 #[inline]
58 fn _lt(x: u8, y: u8) -> u8 {
59 Self::_gt(y, x)
60 }
61
62 #[inline]
63 fn _le(x: u8, y: u8) -> u8 {
64 Self::_ge(y, x)
65 }
66
67 #[inline]
68 fn b64_char_to_byte(c: u8) -> u8 {
69 let x = (Self::_ge(c, b'A') & Self::_le(c, b'Z') & (c.wrapping_sub(b'A')))
70 | (Self::_ge(c, b'a') & Self::_le(c, b'z') & (c.wrapping_sub(b'a'.wrapping_sub(26))))
71 | (Self::_ge(c, b'0') & Self::_le(c, b'9') & (c.wrapping_sub(b'0'.wrapping_sub(52))))
72 | (Self::_eq(c, b'+') & 62)
73 | (Self::_eq(c, b'/') & 63);
74 x | (Self::_eq(x, 0) & (Self::_eq(c, b'A') ^ 0xff))
75 }
76
77 fn skip_padding(b64: &[u8], mut padding_len: usize) -> Result<&[u8], Error> {
78 let b64_len = b64.len();
79 let mut b64_pos = 0usize;
80 while padding_len > 0 {
81 if b64_pos >= b64_len {
82 return Err(Error::InvalidInput);
83 }
84 let c = b64[b64_pos];
85 if c == b'=' {
86 padding_len -= 1
87 } else {
88 return Err(Error::InvalidInput);
89 }
90 b64_pos += 1
91 }
92 Ok(&b64[b64_pos..])
93 }
94
95 pub fn decode<'t>(bin: &'t mut [u8], b64: &[u8]) -> Result<&'t [u8], Error> {
96 let bin_maxlen = bin.len();
97 let mut acc = 0u16;
98 let mut acc_len = 0usize;
99 let mut bin_pos = 0usize;
100 let mut premature_end = None;
101 for (b64_pos, &c) in b64.iter().enumerate() {
102 let d = Self::b64_char_to_byte(c);
103 if d == 0xff {
104 premature_end = Some(b64_pos);
105 break;
106 }
107 acc = (acc << 6) + d as u16;
108 acc_len += 6;
109 if acc_len >= 8 {
110 acc_len -= 8;
111 if bin_pos >= bin_maxlen {
112 return Err(Error::Overflow);
113 }
114 bin[bin_pos] = (acc >> acc_len) as u8;
115 bin_pos += 1;
116 }
117 }
118 if acc_len > 4 || (acc & ((1u16 << acc_len).wrapping_sub(1))) != 0 {
119 return Err(Error::InvalidInput);
120 }
121 let padding_len = acc_len / 2;
122 if let Some(premature_end) = premature_end {
123 let remaining = Self::skip_padding(&b64[premature_end..], padding_len)?;
124 if !remaining.is_empty() {
125 return Err(Error::InvalidInput);
126 }
127 } else if padding_len != 0 {
128 return Err(Error::InvalidInput);
129 }
130 Ok(&bin[..bin_pos])
131 }
132}
133
134pub struct Base64;
135
136impl Decoder for Base64 {
137 #[inline]
138 fn decode<IN: AsRef<[u8]>>(bin: &mut [u8], b64: IN) -> Result<&[u8], Error> {
139 Base64Impl::decode(bin, b64.as_ref())
140 }
141}
142
143#[test]
144fn test_base64_mising_padding() {
145 let missing_padding = "AA";
146 assert!(Base64::decode_to_vec(missing_padding).is_err());
147 let missing_padding = "AAA";
148 assert!(Base64::decode_to_vec(missing_padding).is_err());
149}
150
151#[test]
152fn test_base64_invalid_padding() {
153 let valid_padding = "AA==";
154 assert_eq!(Base64::decode_to_vec(valid_padding), Ok(vec![0u8; 1]));
155 let invalid_padding = "AA=";
156 assert_eq!(
157 Base64::decode_to_vec(invalid_padding),
158 Err(Error::InvalidInput)
159 );
160}