Skip to main content

rustica_keys/ssh/
writer.rs

1use std::collections::HashMap;
2
3use super::pubkey::{PublicKey, PublicKeyKind};
4
5/// A `Writer` is used for encoding a key in OpenSSH compatible format.
6#[derive(Debug)]
7pub struct Writer {
8    inner: Vec<u8>,
9}
10
11impl Writer {
12    /// Creates a new `Writer` instance.
13    ///
14    /// # Example
15    /// ```rust
16    /// # use rustica_keys::ssh::Writer;
17    /// let writer = Writer::new();
18    /// ```
19    pub fn new() -> Writer {
20        Writer { inner: Vec::new() }
21    }
22
23    /// Writes a byte sequence to the underlying vector.
24    /// The value is represented as a the byte sequence length,
25    /// followed by the actual byte sequence.
26    ///
27    /// # Example
28    /// ```rust
29    /// # use rustica_keys::ssh::Writer;
30    /// let mut writer = Writer::new();
31    /// writer.write_bytes(&[0, 0, 0, 42]);
32    /// let bytes = writer.into_bytes();
33    /// assert_eq!(bytes, vec![0, 0, 0, 4, 0, 0, 0, 42]);
34    /// ```
35    pub fn write_bytes(&mut self, val: &[u8]) {
36        let size = val.len() as u32;
37        let mut buf = size.to_be_bytes().to_vec();
38        self.inner.append(&mut buf);
39        self.inner.extend_from_slice(&val);
40    }
41
42    /// Writes a `string` value to the underlying byte sequence.
43    ///
44    /// # Example
45    /// ```rust
46    /// # use rustica_keys::ssh::Writer;
47    /// let mut writer = Writer::new();
48    /// writer.write_string("a test string");
49    /// let bytes = writer.into_bytes();
50    /// assert_eq!(bytes, [0, 0, 0, 13, 97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103]);
51    /// ```
52    pub fn write_string(&mut self, val: &str) {
53        self.write_bytes(val.as_bytes());
54    }
55
56    /// Writes a `u64` value to the underlying byte sequence.
57    ///
58    /// # Example
59    /// ```rust
60    /// # use rustica_keys::ssh::Writer;
61    /// let mut writer = Writer::new();
62    /// writer.write_u64(0xFFFFFFFFFFFFFFFF);
63    /// let bytes = writer.into_bytes();
64    /// assert_eq!(bytes, [255, 255, 255, 255, 255, 255, 255, 255]);
65    /// ```
66    pub fn write_u64(&mut self, val: u64) {
67        let bytes = val.to_be_bytes();
68        self.inner.extend_from_slice(&bytes);
69    }
70
71    /// Writes a `u32` value to the underlying byte sequence.
72    ///
73    /// # Example
74    /// ```rust
75    /// # use rustica_keys::ssh::Writer;
76    /// let mut writer = Writer::new();
77    /// writer.write_u32(0xFFFFFFFF);
78    /// let bytes = writer.into_bytes();
79    /// assert_eq!(bytes, [255, 255, 255, 255]);
80    /// ```
81    pub fn write_u32(&mut self, val: u32) {
82        let bytes = val.to_be_bytes();
83        self.inner.extend_from_slice(&bytes);
84    }
85
86    /// Writes an `mpint` value to the underlying byte sequence.
87    /// If the MSB bit of the first byte is set then the number is
88    /// negative, otherwise it is positive.
89    /// Positive numbers must be preceeded by a leading zero byte according to RFC 4251, section 5.
90    ///
91    /// # Example
92    /// ```rust
93    /// # use rustica_keys::ssh::Writer;
94    /// let mut writer = Writer::new();
95    /// writer.write_mpint(&[1, 0, 1]);
96    /// let bytes = writer.into_bytes();
97    /// assert_eq!(bytes, [0, 0, 0, 3, 1, 0, 1]);
98    /// ```
99    pub fn write_mpint(&mut self, val: &[u8]) {
100        let mut bytes = val.to_vec();
101
102        // If most significant bit is set then prepend a zero byte to
103        // avoid interpretation as a negative number.
104        if val.get(0).unwrap_or(&0) & 0x80 != 0 {
105            bytes.insert(0, 0);
106        }
107
108        self.write_bytes(&bytes);
109    }
110
111    /// Writes a `Vec<String>` to the underlying byte sequence.
112    ///
113    /// # Example
114    /// ```rust
115    /// # use rustica_keys::ssh::Writer;
116    /// let mut writer = Writer::new();
117    /// 
118    /// writer.write_string_vec(&vec![String::from("Test"), String::from("Test")]);
119    /// let bytes = writer.into_bytes();
120    /// assert_eq!(bytes, [0, 0, 0, 16, 0, 0, 0, 4, 84, 101, 115, 116, 0, 0, 0, 4, 84, 101, 115, 116]);
121    /// ```
122    pub fn write_string_vec(&mut self, vec: &[String]) {
123        let total_length = vec.iter().map(|x| x.len()).fold(vec.len()*4, |x, y| x + y) as u32;
124        self.write_u32(total_length);
125
126        for item in vec {
127            self.write_string(item);
128        }
129    }
130
131    /// Writes a `HashMap<String, String>` to the underlying byte sequence.
132    ///
133    /// # Example
134    /// ```rust
135    /// # use rustica_keys::ssh::Writer;
136    /// # use std::collections::HashMap;
137    /// 
138    /// let mut writer = Writer::new();
139    /// let mut example_map = HashMap::new();
140    /// example_map.insert(String::from("Test"), String::from(""));
141    /// writer.write_string_map(&example_map);
142    /// let bytes = writer.into_bytes();
143    /// assert_eq!(bytes, [0, 0, 0, 12, 0, 0, 0, 4, 84, 101, 115, 116, 0, 0, 0, 0]);
144    /// ```
145    pub fn write_string_map(&mut self, map: &HashMap<String, String>) {
146        let total_length = map.iter()
147            .map(|x| x.0.len() + x.1.len() + if !x.1.is_empty() { 4 } else { 0 })
148            .fold(map.len() * 8, |x, y| x + y) as u32;
149
150        self.write_u32(total_length);
151
152        for (k,v) in map {
153            self.write_string(k);
154            if v.is_empty() {
155                self.write_u32(0x0);
156            } else {
157                self.write_u32(v.len() as u32 + 4);
158                self.write_string(v);
159            }
160        }
161    }
162
163    /// Writes a `PublicKey` to the underlying byte sequence.
164    ///
165    /// # Example
166    /// ```
167    /// ```
168    pub fn write_pub_key(&mut self, key: &PublicKey) {
169         // Write the public key
170         match &key.kind {
171            PublicKeyKind::Ecdsa(key) => {
172                self.write_string(key.curve.identifier);
173                self.write_bytes(&key.key);
174            },
175            PublicKeyKind::Rsa(key) => {
176                self.write_bytes(&key.n);
177                self.write_bytes(&key.e);
178            },
179            PublicKeyKind::Ed25519(key) => {
180                self.write_bytes(&key.key);
181            }
182        };
183    }
184
185    /// Converts the `Writer` into a byte sequence.
186    /// This consumes the underlying byte sequence used by the `Writer`.
187    ///
188    /// # Example
189    /// ```rust
190    /// # use rustica_keys::ssh::Writer;
191    /// 
192    /// let mut writer = Writer::new();
193    /// writer.write_string("some data");
194    /// let bytes = writer.into_bytes();
195    /// assert_eq!(bytes, [0, 0, 0, 9, 115, 111, 109, 101, 32, 100, 97, 116, 97]);
196    /// ```
197    pub fn into_bytes(self) -> Vec<u8> {
198        self.inner
199    }
200
201    /// Converts the `Writer` into a byte sequence.
202    /// This consumes the underlying byte sequence used by the `Writer`.
203    ///
204    /// # Example
205    /// ```rust
206    /// # use rustica_keys::ssh::Writer;
207    /// 
208    /// let mut writer = Writer::new();
209    /// writer.write_string("some data");
210    /// let bytes = writer.into_bytes();
211    /// assert_eq!(bytes, [0, 0, 0, 9, 115, 111, 109, 101, 32, 100, 97, 116, 97]);
212    /// ```
213    pub fn as_bytes(&self) -> &[u8] {
214        self.inner.as_slice()
215    }
216}
217
218impl Default for Writer {
219    fn default() -> Self {
220        Writer::new()
221    }
222}