Skip to main content

rustica_keys/ssh/
reader.rs

1use super::error::{Error, ErrorKind, Result};
2use std::convert::TryInto;
3
4/// A `Reader` is used for reading from a byte sequence
5/// representing an encoded OpenSSH public key or certificate.
6#[derive(Debug)]
7pub struct Reader<'a> {
8    inner: &'a [u8],
9    offset: usize,
10}
11
12impl<'a> Reader<'a> {
13    /// Creates a new `Reader` instance from the given byte sequence.
14    ///
15    /// # Example
16    /// ```rust
17    /// # use rustica_keys::ssh::Reader;
18    /// let data = vec![0, 0, 0, 42];
19    /// let mut reader = Reader::new(&data);
20    /// let num = reader.read_u32().unwrap();
21    /// assert_eq!(num, 42);
22    /// ```
23    pub fn new<T: ?Sized + AsRef<[u8]>>(inner: &T) -> Reader {
24        Reader {
25            inner: inner.as_ref(),
26            offset: 0,
27        }
28    }
29
30    /// Sets the `Reader` current offset to a given position.
31    ///
32    /// # Example
33    /// ```rust
34    /// # use rustica_keys::ssh::Reader;
35    /// let data = vec![0, 0, 0, 42];
36    /// let mut reader = Reader::new(&data);
37    /// let num = reader.read_u32().unwrap();
38    /// assert_eq!(num, 42);
39    /// reader.set_offset(0);
40    /// let num_42_again = reader.read_u32().unwrap();
41    /// assert_eq!(num_42_again, 42);
42    /// ```
43    pub fn set_offset(&mut self, offset: usize) -> Result<()> {
44        self.offset = offset;
45
46        Ok(())
47    }
48
49    /// Gets the `Reader` current offset.
50    ///
51    /// # Example
52    /// ```rust
53    /// # use rustica_keys::ssh::Reader;
54    /// let data = vec![0, 0, 0, 42];
55    /// let mut reader = Reader::new(&data);
56    /// let num = reader.read_u32().unwrap();
57    /// assert_eq!(num, 42);
58    /// assert_eq!(reader.get_offset(), 4);
59    /// ```
60    pub fn get_offset(&self) -> usize {
61        self.offset
62    }
63
64    /// Reads a byte buffer from the wrapped byte sequence and
65    /// returns it as a `Vec<u8>`.
66    /// The buffer is represented by it's length as `u32` value
67    /// followed by the actual bytes to read.
68    ///
69    /// # Example
70    /// ```rust
71    /// # use rustica_keys::ssh::Reader;
72    /// let data = vec![0, 0, 0, 13, 97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103];
73    /// let mut reader = Reader::new(&data);
74    /// let bytes = reader.read_bytes().unwrap();
75    /// assert_eq!(bytes, [97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103]);
76    /// ```
77    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
78        if self.offset >= self.inner.len() {
79            return Err(Error::with_kind(ErrorKind::UnexpectedEof));
80        }
81
82        let slice = &self.inner[self.offset..];
83        if slice.len() < 4 {
84            return Err(Error::with_kind(ErrorKind::InvalidFormat));
85        }
86
87        let size = u32::from_be_bytes(slice[..4].try_into().unwrap()) as usize;
88        if slice.len() < size + 4 {
89            return Err(Error::with_kind(ErrorKind::InvalidFormat));
90        }
91
92        self.offset += size + 4;
93        let result = slice[4..size + 4].to_vec();
94
95        Ok(result)
96    }
97
98    /// Reads `len` bytes from the wrapped buffer as raw data
99    /// # Example
100    /// ```rust
101    /// # use rustica_keys::ssh::Reader;
102    /// let data = vec![0, 0, 0, 13, 97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103];
103    /// let mut reader = Reader::new(&data);
104    /// let bytes = reader.read_raw_bytes(4).unwrap();
105    /// assert_eq!(bytes, [0, 0, 0, 13]);
106    /// ```
107    pub fn read_raw_bytes(&mut self, len: usize) -> Result<Vec<u8>> {
108        if self.offset >= self.inner.len() {
109            return Err(Error::with_kind(ErrorKind::UnexpectedEof));
110        }
111
112        if len + self.offset > self.inner.len() {
113            return Err(Error::with_kind(ErrorKind::UnexpectedEof));
114        }
115
116        let slice = &self.inner[self.offset..];
117
118        self.offset += len;
119        let result = slice[..len].to_vec();
120
121        Ok(result)
122    }
123
124    /// Reads an `mpint` value from the wrapped byte sequence.
125    ///
126    /// Drops the leading byte if it's value is zero according to the RFC 4251, section 5.
127    ///
128    /// # Example
129    /// ```rust
130    /// # use rustica_keys::ssh::Reader;
131    /// let data = vec![0, 0, 0, 3, 1, 0, 1];
132    /// let mut reader = Reader::new(&data);
133    /// let mpint = reader.read_mpint().unwrap();
134    /// assert_eq!(mpint, [1, 0, 1]);
135    /// ```
136    pub fn read_mpint(&mut self) -> Result<Vec<u8>> {
137        let bytes = self.read_bytes()?;
138
139        if bytes[0] == 0 {
140            return Ok(bytes[1..].to_vec());
141        }
142
143        Ok(bytes)
144    }
145
146    /// Reads a `string` value from the wrapped byte sequence and
147    /// returns it as a `String`. The value that we read should be a valid UTF-8.
148    ///
149    /// # Example
150    /// ```rust
151    /// # use rustica_keys::ssh::Reader;
152    /// let data = vec![0, 0, 0, 13, 97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103];
153    /// let mut reader = Reader::new(&data);
154    /// let result = reader.read_string().unwrap();
155    /// assert_eq!(result, "a test string");
156    /// ```
157    pub fn read_string(&mut self) -> Result<String> {
158        let bytes = self.read_bytes()?;
159        let result = String::from_utf8(bytes)?;
160
161        Ok(result)
162    }
163
164    /// Read a null terminated string from the reader's buffer.
165    /// This is different than read_string in that the length
166    /// is unknown and will continue until it reads a null byte
167    /// or reaches the end of the data.
168    /// 
169    /// In the event the buffer runs out before a null byte, the offset will be
170    /// reset and an error returned.
171    pub fn read_cstring(&mut self) -> Result<String> {
172        let original_offset = self.offset;
173        let mut s = String::new();
174
175        while self.offset < self.inner.len() {
176            let chr = self.inner[self.offset];
177            if chr == 0x0 {
178                // Count the final null byte as read
179                self.offset += 1;
180                return Ok(s);
181            }
182
183            s.push(chr as char);
184            self.offset += 1;
185        }
186        self.offset = original_offset;
187        Err(Error::with_kind(ErrorKind::UnexpectedEof))
188    }
189
190    /// Reads an `u32` value from the wrapped byte sequence and returns it.
191    ///
192    /// # Example
193    /// ```rust
194    /// # use rustica_keys::ssh::Reader;
195    /// let data = vec![0, 0, 0, 42];
196    /// let mut reader = Reader::new(&data);
197    /// let num = reader.read_u32().unwrap();
198    /// assert_eq!(num, 42);
199    /// ```
200    pub fn read_u32(&mut self) -> Result<u32> {
201        if self.offset >= self.inner.len() {
202            return Err(Error::with_kind(ErrorKind::UnexpectedEof));
203        }
204
205        let slice = &self.inner[self.offset..];
206        if slice.len() < 4 {
207            return Err(Error::with_kind(ErrorKind::InvalidFormat));
208        }
209
210        self.offset += 4;
211        let value = u32::from_be_bytes(slice[..4].try_into().unwrap());
212
213        Ok(value)
214    }
215
216    /// Reads an `u64` value from the wrapped byte sequence and returns it.
217    ///
218    /// # Example
219    /// ```rust
220    /// # use rustica_keys::ssh::Reader;
221    /// let data = vec![0, 0, 0, 0, 0, 0, 0, 42];
222    /// let mut reader = Reader::new(&data);
223    /// let num = reader.read_u64().unwrap();
224    /// assert_eq!(num, 42);
225    /// ```
226    pub fn read_u64(&mut self) -> Result<u64> {
227        if self.offset >= self.inner.len() {
228            return Err(Error::with_kind(ErrorKind::UnexpectedEof));
229        }
230
231        let slice = &self.inner[self.offset..];
232        if slice.len() < 8 {
233            return Err(Error::with_kind(ErrorKind::InvalidFormat));
234        }
235
236        self.offset += 8;
237        let value = u64::from_be_bytes(slice[..8].try_into().unwrap());
238
239        Ok(value)
240    }
241}