lnk_thrussh_encoding/
lib.rs1use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
17use lnk_cryptovec::CryptoVec;
18use thiserror::Error;
19
20#[derive(Debug, Error)]
21pub enum Error {
22 #[error("Index out of bounds")]
24 IndexOutOfBounds,
25}
26
27#[doc(hidden)]
28pub trait Bytes {
29 fn bytes(&self) -> &[u8];
30}
31
32impl<A: AsRef<str>> Bytes for A {
33 fn bytes(&self) -> &[u8] {
34 self.as_ref().as_bytes()
35 }
36}
37
38pub trait Encoding {
40 fn extend_ssh_string(&mut self, s: &[u8]);
42 fn extend_ssh_string_blank(&mut self, s: usize) -> &mut [u8];
44 fn extend_ssh_mpint(&mut self, s: &[u8]);
46 fn extend_list<A: Bytes, I: Iterator<Item = A>>(&mut self, list: I);
48 fn write_empty_list(&mut self);
50}
51
52pub fn mpint_len(s: &[u8]) -> usize {
54 let mut i = 0;
55 while i < s.len() && s[i] == 0 {
56 i += 1
57 }
58 (if s[i] & 0x80 != 0 { 5 } else { 4 }) + s.len() - i
59}
60
61impl Encoding for Vec<u8> {
62 fn extend_ssh_string(&mut self, s: &[u8]) {
63 self.write_u32::<BigEndian>(s.len() as u32).unwrap();
64 self.extend(s);
65 }
66 fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] {
67 self.write_u32::<BigEndian>(len as u32).unwrap();
68 let current = self.len();
69 self.resize(current + len, 0u8);
70 &mut self[current..]
71 }
72 fn extend_ssh_mpint(&mut self, s: &[u8]) {
73 let mut i = 0;
75 while i < s.len() && s[i] == 0 {
76 i += 1
77 }
78 if s[i] & 0x80 != 0 {
80 self.write_u32::<BigEndian>((s.len() - i + 1) as u32)
81 .unwrap();
82 self.push(0)
83 } else {
84 self.write_u32::<BigEndian>((s.len() - i) as u32).unwrap();
85 }
86 self.extend(&s[i..]);
87 }
88
89 fn extend_list<A: Bytes, I: Iterator<Item = A>>(&mut self, list: I) {
90 let len0 = self.len();
91 self.extend(&[0, 0, 0, 0]);
92 let mut first = true;
93 for i in list {
94 if !first {
95 self.push(b',')
96 } else {
97 first = false;
98 }
99 self.extend(i.bytes())
100 }
101 let len = (self.len() - len0 - 4) as u32;
102
103 BigEndian::write_u32(&mut self[len0..], len);
104 }
105
106 fn write_empty_list(&mut self) {
107 self.extend(&[0, 0, 0, 0]);
108 }
109}
110
111impl Encoding for CryptoVec {
112 fn extend_ssh_string(&mut self, s: &[u8]) {
113 self.push_u32_be(s.len() as u32);
114 self.extend(s);
115 }
116 fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] {
117 self.push_u32_be(len as u32);
118 let current = self.len();
119 self.resize(current + len);
120 &mut self[current..]
121 }
122 fn extend_ssh_mpint(&mut self, s: &[u8]) {
123 let mut i = 0;
125 while i < s.len() && s[i] == 0 {
126 i += 1
127 }
128 if s[i] & 0x80 != 0 {
130 self.push_u32_be((s.len() - i + 1) as u32);
131 self.push(0)
132 } else {
133 self.push_u32_be((s.len() - i) as u32);
134 }
135 self.extend(&s[i..]);
136 }
137
138 fn extend_list<A: Bytes, I: Iterator<Item = A>>(&mut self, list: I) {
139 let len0 = self.len();
140 self.extend(&[0, 0, 0, 0]);
141 let mut first = true;
142 for i in list {
143 if !first {
144 self.push(b',')
145 } else {
146 first = false;
147 }
148 self.extend(i.bytes())
149 }
150 let len = (self.len() - len0 - 4) as u32;
151
152 BigEndian::write_u32(&mut self[len0..], len);
153 }
154
155 fn write_empty_list(&mut self) {
156 self.extend(&[0, 0, 0, 0]);
157 }
158}
159
160pub trait Reader {
162 fn reader<'a>(&'a self, starting_at: usize) -> Position<'a>;
164}
165
166impl Reader for CryptoVec {
167 fn reader<'a>(&'a self, starting_at: usize) -> Position<'a> {
168 Position {
169 s: &self,
170 position: starting_at,
171 }
172 }
173}
174
175impl Reader for [u8] {
176 fn reader<'a>(&'a self, starting_at: usize) -> Position<'a> {
177 Position {
178 s: self,
179 position: starting_at,
180 }
181 }
182}
183
184#[derive(Debug)]
186pub struct Position<'a> {
187 s: &'a [u8],
188 #[doc(hidden)]
189 pub position: usize,
190}
191impl<'a> Position<'a> {
192 pub fn read_string(&mut self) -> Result<&'a [u8], Error> {
194 let len = self.read_u32()? as usize;
195 if self.position + len <= self.s.len() {
196 let result = &self.s[self.position..(self.position + len)];
197 self.position += len;
198 Ok(result)
199 } else {
200 Err(Error::IndexOutOfBounds)
201 }
202 }
203 pub fn read_u32(&mut self) -> Result<u32, Error> {
205 if self.position + 4 <= self.s.len() {
206 let u = BigEndian::read_u32(&self.s[self.position..]);
207 self.position += 4;
208 Ok(u)
209 } else {
210 Err(Error::IndexOutOfBounds)
211 }
212 }
213 pub fn read_byte(&mut self) -> Result<u8, Error> {
215 if self.position + 1 <= self.s.len() {
216 let u = self.s[self.position];
217 self.position += 1;
218 Ok(u)
219 } else {
220 Err(Error::IndexOutOfBounds)
221 }
222 }
223
224 pub fn read_mpint(&mut self) -> Result<&'a [u8], Error> {
226 let len = self.read_u32()? as usize;
227 if self.position + len <= self.s.len() {
228 let result = &self.s[self.position..(self.position + len)];
229 self.position += len;
230 Ok(result)
231 } else {
232 Err(Error::IndexOutOfBounds)
233 }
234 }
235}