1use std::ops::DerefMut;
16
17use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
18use thiserror::Error;
19use zeroize::Zeroizing;
20
21pub type Buffer = Zeroizing<Vec<u8>>;
23
24#[derive(Debug, Error)]
25pub enum Error {
26 #[error("Index out of bounds")]
28 IndexOutOfBounds,
29}
30
31pub trait Encodable: Sized {
32 type Error: std::error::Error + Send + Sync + 'static;
33
34 fn read(reader: &mut Cursor) -> Result<Self, Self::Error>;
36 fn write<E: Encoding>(&self, buf: &mut E);
38}
39
40pub trait Encoding {
42 fn extend_ssh_string(&mut self, s: &[u8]);
44 fn extend_ssh_string_blank(&mut self, s: usize) -> &mut [u8];
46 fn extend_ssh_mpint(&mut self, s: &[u8]);
48 fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I);
50 fn extend_u32(&mut self, u: u32);
52 fn write_empty_list(&mut self);
54 fn write_len(&mut self);
56}
57
58pub fn mpint_len(s: &[u8]) -> usize {
60 let mut i = 0;
61 while i < s.len() && s[i] == 0 {
62 i += 1
63 }
64 (if s[i] & 0x80 != 0 { 5 } else { 4 }) + s.len() - i
65}
66
67impl Encoding for Vec<u8> {
68 fn extend_ssh_string(&mut self, s: &[u8]) {
69 self.write_u32::<BigEndian>(s.len() as u32).unwrap();
70 self.extend(s);
71 }
72
73 fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] {
74 self.write_u32::<BigEndian>(len as u32).unwrap();
75 let current = self.len();
76 self.resize(current + len, 0u8);
77
78 &mut self[current..]
79 }
80
81 fn extend_ssh_mpint(&mut self, s: &[u8]) {
82 let mut i = 0;
84 while i < s.len() && s[i] == 0 {
85 i += 1
86 }
87 if s[i] & 0x80 != 0 {
89 self.write_u32::<BigEndian>((s.len() - i + 1) as u32)
90 .unwrap();
91 self.push(0)
92 } else {
93 self.write_u32::<BigEndian>((s.len() - i) as u32).unwrap();
94 }
95 self.extend(&s[i..]);
96 }
97
98 fn extend_u32(&mut self, s: u32) {
99 let mut buf = [0x0; 4];
100 BigEndian::write_u32(&mut buf, s);
101 self.extend(buf);
102 }
103
104 fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I) {
105 let len0 = self.len();
106 self.extend([0, 0, 0, 0]);
107
108 let mut first = true;
109 for i in list {
110 if !first {
111 self.push(b',')
112 } else {
113 first = false;
114 }
115 self.extend(i)
116 }
117 let len = (self.len() - len0 - 4) as u32;
118
119 BigEndian::write_u32(&mut self[len0..], len);
120 }
121
122 fn write_empty_list(&mut self) {
123 self.extend([0, 0, 0, 0]);
124 }
125
126 fn write_len(&mut self) {
127 let len = self.len() - 4;
128 BigEndian::write_u32(&mut self[..], len as u32);
129 }
130}
131
132impl Encoding for Buffer {
133 fn extend_ssh_string(&mut self, s: &[u8]) {
134 self.deref_mut().extend_ssh_string(s)
135 }
136
137 fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] {
138 self.deref_mut().extend_ssh_string_blank(len)
139 }
140
141 fn extend_ssh_mpint(&mut self, s: &[u8]) {
142 self.deref_mut().extend_ssh_mpint(s)
143 }
144
145 fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I) {
146 self.deref_mut().extend_list(list)
147 }
148
149 fn write_empty_list(&mut self) {
150 self.deref_mut().write_empty_list()
151 }
152
153 fn extend_u32(&mut self, s: u32) {
154 self.deref_mut().extend_u32(s);
155 }
156
157 fn write_len(&mut self) {
158 self.deref_mut().write_len()
159 }
160}
161
162pub trait Reader {
164 fn reader(&self, starting_at: usize) -> Cursor;
166}
167
168impl Reader for Buffer {
169 fn reader(&self, starting_at: usize) -> Cursor {
170 Cursor {
171 s: self,
172 position: starting_at,
173 }
174 }
175}
176
177impl Reader for [u8] {
178 fn reader(&self, starting_at: usize) -> Cursor {
179 Cursor {
180 s: self,
181 position: starting_at,
182 }
183 }
184}
185
186#[derive(Debug)]
188pub struct Cursor<'a> {
189 s: &'a [u8],
190 #[doc(hidden)]
191 pub position: usize,
192}
193
194impl<'a> Cursor<'a> {
195 pub fn read_string(&mut self) -> Result<&'a [u8], Error> {
197 let len = self.read_u32()? as usize;
198 if self.position + len <= self.s.len() {
199 let result = &self.s[self.position..(self.position + len)];
200 self.position += len;
201 Ok(result)
202 } else {
203 Err(Error::IndexOutOfBounds)
204 }
205 }
206
207 pub fn read_u32(&mut self) -> Result<u32, Error> {
209 if self.position + 4 <= self.s.len() {
210 let u = BigEndian::read_u32(&self.s[self.position..]);
211 self.position += 4;
212 Ok(u)
213 } else {
214 Err(Error::IndexOutOfBounds)
215 }
216 }
217
218 pub fn read_byte(&mut self) -> Result<u8, Error> {
220 if self.position < self.s.len() {
221 let u = self.s[self.position];
222 self.position += 1;
223 Ok(u)
224 } else {
225 Err(Error::IndexOutOfBounds)
226 }
227 }
228
229 pub fn read_bytes<const S: usize>(&mut self) -> Result<[u8; S], Error> {
230 let mut buf = [0; S];
231 for b in buf.iter_mut() {
232 *b = self.read_byte()?;
233 }
234 Ok(buf)
235 }
236
237 pub fn read_mpint(&mut self) -> Result<&'a [u8], Error> {
239 let len = self.read_u32()? as usize;
240 if self.position + len <= self.s.len() {
241 let result = &self.s[self.position..(self.position + len)];
242 self.position += len;
243 Ok(result)
244 } else {
245 Err(Error::IndexOutOfBounds)
246 }
247 }
248}