ssh_encoding/encode.rs
1//! Encoder-side implementation of the SSH protocol's data type representations
2//! as described in [RFC4251 § 5].
3//!
4//! [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
5
6use crate::{Error, checked::CheckedSum, writer::Writer};
7use core::str;
8
9#[cfg(feature = "alloc")]
10use alloc::{string::String, vec::Vec};
11
12#[cfg(feature = "bytes")]
13use bytes::{Bytes, BytesMut};
14
15/// Encoding trait.
16///
17/// This trait describes how to encode a given type.
18pub trait Encode {
19 /// Get the length of this type encoded in bytes, prior to Base64 encoding.
20 fn encoded_len(&self) -> Result<usize, Error>;
21
22 /// Encode this value using the provided [`Writer`].
23 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error>;
24
25 /// Return the length of this type after encoding when prepended with a
26 /// `uint32` length prefix.
27 fn encoded_len_prefixed(&self) -> Result<usize, Error> {
28 [4, self.encoded_len()?].checked_sum()
29 }
30
31 /// Encode this value, first prepending a `uint32` length prefix
32 /// set to [`Encode::encoded_len`].
33 fn encode_prefixed(&self, writer: &mut impl Writer) -> Result<(), Error> {
34 self.encoded_len()?.encode(writer)?;
35 self.encode(writer)
36 }
37
38 /// Encode this value, returning a `Vec<u8>` containing the encoded message.
39 #[cfg(feature = "alloc")]
40 fn encode_vec(&self) -> Result<Vec<u8>, Error> {
41 let mut ret = Vec::with_capacity(self.encoded_len()?);
42 self.encode(&mut ret)?;
43 Ok(ret)
44 }
45
46 /// Encode this value, returning a [`BytesMut`] containing the encoded message.
47 #[cfg(feature = "bytes")]
48 fn encode_bytes(&self) -> Result<BytesMut, Error> {
49 let mut ret = BytesMut::with_capacity(self.encoded_len()?);
50 self.encode(&mut ret)?;
51 Ok(ret)
52 }
53}
54
55/// Encode a single `byte` to the writer.
56impl Encode for u8 {
57 fn encoded_len(&self) -> Result<usize, Error> {
58 Ok(1)
59 }
60
61 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
62 writer.write(&[*self])
63 }
64}
65
66/// Encode a `boolean` as described in [RFC4251 § 5]:
67///
68/// > A boolean value is stored as a single byte. The value 0
69/// > represents FALSE, and the value 1 represents TRUE. All non-zero
70/// > values MUST be interpreted as TRUE; however, applications MUST NOT
71/// > store values other than 0 and 1.
72///
73/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
74impl Encode for bool {
75 fn encoded_len(&self) -> Result<usize, Error> {
76 Ok(1)
77 }
78
79 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
80 if *self {
81 1u8.encode(writer)
82 } else {
83 0u8.encode(writer)
84 }
85 }
86}
87
88/// Encode a `uint32` as described in [RFC4251 § 5]:
89///
90/// > Represents a 32-bit unsigned integer. Stored as four bytes in the
91/// > order of decreasing significance (network byte order).
92/// > For example: the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 aa.
93///
94/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
95impl Encode for u32 {
96 fn encoded_len(&self) -> Result<usize, Error> {
97 Ok(4)
98 }
99
100 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
101 writer.write(&self.to_be_bytes())
102 }
103}
104
105/// Encode a `uint64` as described in [RFC4251 § 5]:
106///
107/// > Represents a 64-bit unsigned integer. Stored as eight bytes in
108/// > the order of decreasing significance (network byte order).
109///
110/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
111impl Encode for u64 {
112 fn encoded_len(&self) -> Result<usize, Error> {
113 Ok(8)
114 }
115
116 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
117 writer.write(&self.to_be_bytes())
118 }
119}
120
121/// Encode a `usize` as a `uint32` as described in [RFC4251 § 5].
122///
123/// Uses [`Encode`] impl on `u32` after converting from a `usize`, handling
124/// potential overflow if `usize` is bigger than `u32`.
125///
126/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
127impl Encode for usize {
128 fn encoded_len(&self) -> Result<usize, Error> {
129 Ok(4)
130 }
131
132 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
133 u32::try_from(*self)?.encode(writer)
134 }
135}
136
137/// Encodes `[u8]` into `string` as described in [RFC4251 § 5]:
138///
139/// > Arbitrary length binary string. Strings are allowed to contain
140/// > arbitrary binary data, including null characters and 8-bit
141/// > characters. They are stored as a uint32 containing its length
142/// > (number of bytes that follow) and zero (= empty string) or more
143/// > bytes that are the value of the string. Terminating null
144/// > characters are not used.
145///
146/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
147impl Encode for [u8] {
148 fn encoded_len(&self) -> Result<usize, Error> {
149 [4, self.len()].checked_sum()
150 }
151
152 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
153 self.len().encode(writer)?;
154 writer.write(self)
155 }
156}
157
158/// Encodes byte array using `byte[n]` encoding as described in [RFC4251 § 5]:
159///
160/// > A byte represents an arbitrary 8-bit value (octet). Fixed length
161/// > data is sometimes represented as an array of bytes, written
162/// > `byte[n]`, where n is the number of bytes in the array.
163///
164/// Note that unlike `string`, this type is encoded without a length prefix,
165/// but instead implicitly obtains its length as `N`.
166///
167/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
168impl<const N: usize> Encode for [u8; N] {
169 fn encoded_len(&self) -> Result<usize, Error> {
170 Ok(N)
171 }
172
173 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
174 writer.write(self)
175 }
176}
177
178/// Encode a `string` as described in [RFC4251 § 5]:
179///
180/// > Arbitrary length binary string. Strings are allowed to contain
181/// > arbitrary binary data, including null characters and 8-bit
182/// > characters. They are stored as a uint32 containing its length
183/// > (number of bytes that follow) and zero (= empty string) or more
184/// > bytes that are the value of the string. Terminating null
185/// > characters are not used.
186/// >
187/// > Strings are also used to store text. In that case, US-ASCII is
188/// > used for internal names, and ISO-10646 UTF-8 for text that might
189/// > be displayed to the user. The terminating null character SHOULD
190/// > NOT normally be stored in the string. For example: the US-ASCII
191/// > string "testing" is represented as 00 00 00 07 t e s t i n g. The
192/// > UTF-8 mapping does not alter the encoding of US-ASCII characters.
193///
194/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
195impl Encode for &str {
196 fn encoded_len(&self) -> Result<usize, Error> {
197 self.as_bytes().encoded_len()
198 }
199
200 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
201 self.as_bytes().encode(writer)
202 }
203}
204
205#[cfg(feature = "alloc")]
206impl Encode for Vec<u8> {
207 fn encoded_len(&self) -> Result<usize, Error> {
208 self.as_slice().encoded_len()
209 }
210
211 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
212 self.as_slice().encode(writer)
213 }
214}
215
216#[cfg(feature = "alloc")]
217impl Encode for String {
218 fn encoded_len(&self) -> Result<usize, Error> {
219 self.as_str().encoded_len()
220 }
221
222 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
223 self.as_str().encode(writer)
224 }
225}
226
227#[cfg(feature = "alloc")]
228impl Encode for Vec<String> {
229 fn encoded_len(&self) -> Result<usize, Error> {
230 self.iter().try_fold(4usize, |acc, string| {
231 acc.checked_add(string.encoded_len()?).ok_or(Error::Length)
232 })
233 }
234
235 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
236 self.encoded_len()?
237 .checked_sub(4)
238 .ok_or(Error::Length)?
239 .encode(writer)?;
240
241 for entry in self {
242 entry.encode(writer)?;
243 }
244
245 Ok(())
246 }
247}
248
249#[cfg(feature = "bytes")]
250impl Encode for Bytes {
251 fn encoded_len(&self) -> Result<usize, Error> {
252 self.as_ref().encoded_len()
253 }
254
255 fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
256 self.as_ref().encode(writer)
257 }
258}