ssh/model/data.rs
1use std::ops::{Deref, DerefMut};
2
3use crate::error::SshResult;
4
5use super::Packet;
6
7/// Data Type Representations Used in the SSH Protocols
8/// <https://www.rfc-editor.org/rfc/rfc4251#section-5>
9
10/// byte
11///
12/// A byte represents an arbitrary 8-bit value (octet). Fixed length
13/// data is sometimes represented as an array of bytes, written
14/// byte[n], where n is the number of bytes in the array.
15///
16/// **boolean**
17///
18/// A boolean value is stored as a single byte. The value 0
19/// represents FALSE, and the value 1 represents TRUE. All non-zero
20/// values MUST be interpreted as TRUE; however, applications MUST NOT
21/// store values other than 0 and 1.
22///
23/// **uint32**
24///
25/// Represents a 32-bit unsigned integer. Stored as four bytes in the
26/// order of decreasing significance (network byte order). For
27/// example: the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4
28/// aa.
29///
30/// **uint64**
31///
32/// Represents a 64-bit unsigned integer. Stored as eight bytes in
33/// the order of decreasing significance (network byte order).
34///
35/// **string**
36///
37/// Arbitrary length binary string. Strings are allowed to contain
38/// arbitrary binary data, including null characters and 8-bit
39/// characters. They are stored as a uint32 containing its length
40/// (number of bytes that follow) and zero (= empty string) or more
41/// bytes that are the value of the string. Terminating null
42/// characters are not used.
43///
44/// Strings are also used to store text. In that case, US-ASCII is
45/// used for internal names, and ISO-10646 UTF-8 for text that might
46/// be displayed to the user. The terminating null character SHOULD
47/// NOT normally be stored in the string. For example: the US-ASCII
48/// string "testing" is represented as 00 00 00 07 t e s t i n g. The
49/// UTF-8 mapping does not alter the encoding of US-ASCII characters.
50///
51/// **mpint**
52///
53/// Represents multiple precision integers in two's complement format,
54/// stored as a string, 8 bits per byte, MSB first. Negative numbers
55/// have the value 1 as the most significant bit of the first byte of
56/// the data partition. If the most significant bit would be set for
57/// a positive number, the number MUST be preceded by a zero byte.
58/// Unnecessary leading bytes with the value 0 or 255 MUST NOT be
59/// included. The value zero MUST be stored as a string with zero
60/// bytes of data.
61///
62/// By convention, a number that is used in modular computations in
63/// Z_n SHOULD be represented in the range 0 <= x < n.
64///
65/// Examples:
66///
67/// value (hex) representation (hex)
68/// ----------- --------------------
69/// 0 00 00 00 00
70/// 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7
71/// 80 00 00 00 02 00 80
72/// -1234 00 00 00 02 ed cc
73/// -deadbeef 00 00 00 05 ff 21 52 41 11
74///
75/// **name-list**
76///
77/// A string containing a comma-separated list of names. A name-list
78/// is represented as a uint32 containing its length (number of bytes
79/// that follow) followed by a comma-separated list of zero or more
80/// names. A name MUST have a non-zero length, and it MUST NOT
81/// contain a comma (","). As this is a list of names, all of the
82/// elements contained are names and MUST be in US-ASCII. Context may
83/// impose additional restrictions on the names. For example, the
84/// names in a name-list may have to be a list of valid algorithm
85/// identifiers (see Section 6 below), or a list of [RFC3066] language
86/// tags. The order of the names in a name-list may or may not be
87/// significant. Again, this depends on the context in which the list
88/// is used. Terminating null characters MUST NOT be used, neither
89/// for the individual names, nor for the list as a whole.
90///
91/// Examples:
92///
93/// value representation (hex)
94/// ----- --------------------
95/// (), the empty name-list 00 00 00 00
96/// ("zlib") 00 00 00 04 7a 6c 69 62
97/// ("zlib,none") 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65
98
99#[derive(Debug, Clone)]
100pub(crate) struct Data(Vec<u8>);
101
102impl Default for Data {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108impl Data {
109 pub fn new() -> Data {
110 Data(Vec::new())
111 }
112
113 #[allow(clippy::uninit_vec)]
114 pub fn uninit_new(len: usize) -> Data {
115 let mut v = Vec::with_capacity(len);
116 unsafe { v.set_len(len) }
117 Data(v)
118 }
119
120 // write uint8
121 pub fn put_u8(&mut self, v: u8) -> &mut Self {
122 self.0.push(v);
123 self
124 }
125
126 // write uint32
127 pub fn put_u32(&mut self, v: u32) -> &mut Self {
128 let vec = v.to_be_bytes().to_vec();
129 self.0.extend(&vec);
130 self
131 }
132
133 // write string
134 pub fn put_str(&mut self, str: &str) -> &mut Self {
135 let v = str.as_bytes();
136 self.put_u32(v.len() as u32);
137 self.0.extend(v);
138 self
139 }
140
141 // write [bytes]
142 pub fn put_u8s(&mut self, v: &[u8]) -> &mut Self {
143 self.put_u32(v.len() as u32);
144 self.0.extend(v);
145 self
146 }
147
148 // write mpint
149 pub fn put_mpint(&mut self, v: &[u8]) -> Vec<u8> {
150 let mut result: Vec<u8> = Vec::new();
151 // 0x80 = 128
152 if v[0] & 0x80 != 0 {
153 result.push(0);
154 }
155 result.extend(v);
156 self.put_u8s(&result).to_vec()
157 }
158
159 // skip `size`
160 pub fn skip(&mut self, size: usize) {
161 self.0.drain(..size);
162 }
163
164 // get uint8
165 pub fn get_u8(&mut self) -> u8 {
166 self.0.remove(0)
167 }
168
169 // get uint32
170 pub fn get_u32(&mut self) -> u32 {
171 let u32_buf = self.0.drain(..4).collect::<Vec<u8>>();
172 u32::from_be_bytes(u32_buf.try_into().unwrap())
173 }
174
175 // get [bytes]
176 pub fn get_u8s(&mut self) -> Vec<u8> {
177 let len = self.get_u32() as usize;
178 let bytes = self.0.drain(..len).collect::<Vec<u8>>();
179 bytes
180 }
181
182 pub fn into_inner(self) -> Vec<u8> {
183 self.0
184 }
185}
186
187impl From<Vec<u8>> for Data {
188 fn from(v: Vec<u8>) -> Self {
189 Data(v)
190 }
191}
192
193impl From<&[u8]> for Data {
194 fn from(v: &[u8]) -> Self {
195 Data(v.into())
196 }
197}
198
199impl From<Data> for Vec<u8> {
200 fn from(data: Data) -> Self {
201 data.0
202 }
203}
204
205impl Deref for Data {
206 type Target = Vec<u8>;
207
208 fn deref(&self) -> &Self::Target {
209 &self.0
210 }
211}
212
213impl DerefMut for Data {
214 fn deref_mut(&mut self) -> &mut Self::Target {
215 &mut self.0
216 }
217}
218
219impl<'a> Packet<'a> for Data {
220 fn pack(self, client: &'a mut crate::client::Client) -> super::packet::SecPacket<'a> {
221 (self, client).into()
222 }
223 fn unpack(pkt: super::packet::SecPacket) -> SshResult<Self>
224 where
225 Self: Sized,
226 {
227 Ok(pkt.into_inner())
228 }
229}