ssh_key/decode.rs
1//! Decoder-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::{reader::Reader, Error, Result};
7
8#[cfg(feature = "alloc")]
9use alloc::{string::String, vec::Vec};
10
11/// Maximum size of a `usize` this library will accept.
12const MAX_SIZE: usize = 0xFFFFF;
13
14/// Decoder trait.
15///
16/// This trait describes how to decode a given type.
17pub(crate) trait Decode: Sized {
18 /// Attempt to decode a value of this type using the provided [`Decoder`].
19 fn decode(reader: &mut impl Reader) -> Result<Self>;
20}
21
22/// Decode a single `byte` from the input data.
23impl Decode for u8 {
24 fn decode(reader: &mut impl Reader) -> Result<Self> {
25 let mut buf = [0];
26 reader.read(&mut buf)?;
27 Ok(buf[0])
28 }
29}
30
31/// Decode a `uint32` as described in [RFC4251 § 5]:
32///
33/// > Represents a 32-bit unsigned integer. Stored as four bytes in the
34/// > order of decreasing significance (network byte order).
35/// > For example: the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 aa.
36///
37/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
38impl Decode for u32 {
39 fn decode(reader: &mut impl Reader) -> Result<Self> {
40 let mut bytes = [0u8; 4];
41 reader.read(&mut bytes)?;
42 Ok(u32::from_be_bytes(bytes))
43 }
44}
45
46/// Decode a `uint64` as described in [RFC4251 § 5]:
47///
48/// > Represents a 64-bit unsigned integer. Stored as eight bytes in
49/// > the order of decreasing significance (network byte order).
50///
51/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
52impl Decode for u64 {
53 fn decode(reader: &mut impl Reader) -> Result<Self> {
54 let mut bytes = [0u8; 8];
55 reader.read(&mut bytes)?;
56 Ok(u64::from_be_bytes(bytes))
57 }
58}
59
60/// Decode a `usize`.
61///
62/// Uses [`Decode`] impl on `u32` and then converts to a `usize`, handling
63/// potential overflow if `usize` is smaller than `u32`.
64///
65/// Enforces a library-internal limit of 1048575, as the main use case for
66/// `usize` is length prefixes.
67impl Decode for usize {
68 fn decode(reader: &mut impl Reader) -> Result<Self> {
69 let n = usize::try_from(u32::decode(reader)?)?;
70
71 if n <= MAX_SIZE {
72 Ok(n)
73 } else {
74 Err(Error::Length)
75 }
76 }
77}
78
79/// Decodes a byte array from `byte[n]` as described in [RFC4251 § 5]:
80///
81/// > A byte represents an arbitrary 8-bit value (octet). Fixed length
82/// > data is sometimes represented as an array of bytes, written
83/// > byte[n], where n is the number of bytes in the array.
84///
85/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
86impl<const N: usize> Decode for [u8; N] {
87 fn decode(reader: &mut impl Reader) -> Result<Self> {
88 reader.read_nested(|reader| {
89 let mut result = [(); N].map(|_| 0);
90 reader.read(&mut result)?;
91 Ok(result)
92 })
93 }
94}
95
96/// Decodes `Vec<u8>` from `byte[n]` as described in [RFC4251 § 5]:
97///
98/// > A byte represents an arbitrary 8-bit value (octet). Fixed length
99/// > data is sometimes represented as an array of bytes, written
100/// > byte[n], where n is the number of bytes in the array.
101///
102/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
103#[cfg(feature = "alloc")]
104#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
105impl Decode for Vec<u8> {
106 fn decode(reader: &mut impl Reader) -> Result<Self> {
107 reader.read_nested(|reader| {
108 let mut result = vec![0u8; reader.remaining_len()];
109 reader.read(&mut result)?;
110 Ok(result)
111 })
112 }
113}
114
115#[cfg(feature = "alloc")]
116#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
117impl Decode for String {
118 fn decode(reader: &mut impl Reader) -> Result<Self> {
119 String::from_utf8(Vec::decode(reader)?).map_err(|_| Error::CharacterEncoding)
120 }
121}
122
123#[cfg(feature = "alloc")]
124#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
125impl Decode for Vec<String> {
126 fn decode(reader: &mut impl Reader) -> Result<Self> {
127 reader.read_nested(|reader| {
128 let mut entries = Self::new();
129
130 while !reader.is_finished() {
131 entries.push(String::decode(reader)?);
132 }
133
134 Ok(entries)
135 })
136 }
137}