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}