1mod onion_announce_request;
5mod onion_announce_response;
6mod inner_onion_request;
7mod inner_onion_response;
8mod onion_data_request;
9mod onion_data_response;
10mod onion_request_0;
11mod onion_request_1;
12mod onion_request_2;
13mod onion_response_1;
14mod onion_response_2;
15mod onion_response_3;
16mod friend_request;
17
18pub use self::onion_announce_request::*;
19pub use self::onion_announce_response::*;
20pub use self::inner_onion_request::*;
21pub use self::inner_onion_response::*;
22pub use self::onion_data_request::*;
23pub use self::onion_data_response::*;
24pub use self::onion_request_0::*;
25pub use self::onion_request_1::*;
26pub use self::onion_request_2::*;
27pub use self::onion_response_1::*;
28pub use self::onion_response_2::*;
29pub use self::onion_response_3::*;
30pub use self::friend_request::*;
31
32use tox_binary_io::*;
33use tox_crypto::*;
34use crate::dht::packed_node::PackedNode;
35use crate::ip_port::*;
36
37use nom::{
38 named,
39 do_parse,
40 tag,
41 call,
42 alt,
43 map,
44 map_res,
45 flat_map,
46 cond,
47 switch,
48 take,
49 value,
50 verify,
51 eof
52};
53
54use cookie_factory::{
55 do_gen,
56 gen_slice,
57 gen_call,
58 gen_cond,
59 gen_be_u8,
60 gen_le_u64,
61 gen_many_ref
62};
63
64use nom::{
65 Err,
66 number::complete::le_u8,
67 combinator::{rest, rest_len},
68};
69use std::io::{Error, ErrorKind};
70
71const ONION_SEND_BASE: usize = PUBLICKEYBYTES + SIZE_IPPORT + MACBYTES;
72const ONION_SEND_1: usize = secretbox::NONCEBYTES + ONION_SEND_BASE * 3;
73const MAX_ONION_DATA_SIZE: usize = ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1); const MIN_ONION_DATA_REQUEST_SIZE: usize = 1 + PUBLICKEYBYTES + secretbox::NONCEBYTES + PUBLICKEYBYTES + MACBYTES; pub const MAX_DATA_REQUEST_SIZE: usize = MAX_ONION_DATA_SIZE - MIN_ONION_DATA_REQUEST_SIZE;
77pub const MIN_ONION_DATA_RESPONSE_SIZE: usize = PUBLICKEYBYTES + MACBYTES;
79pub const MAX_ONION_CLIENT_DATA_SIZE: usize = MAX_DATA_REQUEST_SIZE - MIN_ONION_DATA_RESPONSE_SIZE;
81
82pub const ONION_RETURN_1_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES; pub const ONION_RETURN_2_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES + ONION_RETURN_1_SIZE; pub const ONION_RETURN_3_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES + ONION_RETURN_2_SIZE; pub const ONION_MAX_PACKET_SIZE: usize = 1400;
92
93#[derive(Clone, Debug, Eq, PartialEq)]
113pub struct OnionReturn {
114 pub nonce: secretbox::Nonce,
116 pub payload: Vec<u8>
118}
119
120impl FromBytes for OnionReturn {
121 named!(from_bytes<OnionReturn>, do_parse!(
122 nonce: call!(secretbox::Nonce::from_bytes) >>
123 payload: rest >>
124 (OnionReturn { nonce, payload: payload.to_vec() })
125 ));
126}
127
128impl ToBytes for OnionReturn {
129 fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
130 do_gen!(buf,
131 gen_slice!(self.nonce.as_ref()) >>
132 gen_slice!(self.payload.as_slice())
133 )
134 }
135}
136
137impl OnionReturn {
138 #[allow(clippy::needless_pass_by_value)]
139 fn inner_to_bytes<'a>(ip_port: &IpPort, inner: Option<&OnionReturn>, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
140 do_gen!(buf,
141 gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf, IpPortPadding::WithPadding), ip_port) >>
142 gen_call!(|buf, inner| match inner {
143 Some(inner) => OnionReturn::to_bytes(inner, buf),
144 None => Ok(buf)
145 }, inner)
146 )
147 }
148
149 named!(inner_from_bytes<(IpPort, Option<OnionReturn>)>, do_parse!(
150 ip_port: call!(IpPort::from_bytes, IpPortPadding::WithPadding) >>
151 rest_len: rest_len >>
152 inner: cond!(rest_len > 0, OnionReturn::from_bytes) >>
153 (ip_port, inner)
154 ));
155
156 pub fn new(symmetric_key: &secretbox::Key, ip_port: &IpPort, inner: Option<&OnionReturn>) -> OnionReturn {
158 let nonce = secretbox::gen_nonce();
159 let mut buf = [0; ONION_RETURN_2_SIZE + SIZE_IPPORT];
160 let (_, size) = OnionReturn::inner_to_bytes(ip_port, inner, (&mut buf, 0)).unwrap();
161 let payload = secretbox::seal(&buf[..size], &nonce, symmetric_key);
162
163 OnionReturn { nonce, payload }
164 }
165
166 pub fn get_payload(&self, symmetric_key: &secretbox::Key) -> Result<(IpPort, Option<OnionReturn>), Error> {
174 let decrypted = secretbox::open(&self.payload, &self.nonce, symmetric_key)
175 .map_err(|()| {
176 Error::new(ErrorKind::Other, "OnionReturn decrypt error.")
177 })?;
178 match OnionReturn::inner_from_bytes(&decrypted) {
179 Err(Err::Incomplete(e)) => {
180 Err(Error::new(ErrorKind::Other,
181 format!("Inner onion return deserialize error: {:?}", e)))
182 },
183 Err(Err::Error(e)) => {
184 Err(Error::new(ErrorKind::Other,
185 format!("Inner onion return deserialize error: {:?}", e)))
186 },
187 Err(Err::Failure(e)) => {
188 Err(Error::new(ErrorKind::Other,
189 format!("Inner onion return deserialize error: {:?}", e)))
190 },
191 Ok((_, inner)) => {
192 Ok(inner)
193 }
194 }
195 }
196}
197
198#[derive(Clone, Copy, Debug, Eq, PartialEq)]
204pub enum AnnounceStatus {
205 Failed = 0,
207 Found = 1,
209 Announced = 2
211}
212
213impl FromBytes for AnnounceStatus {
214 named!(from_bytes<AnnounceStatus>, switch!(le_u8,
215 0 => value!(AnnounceStatus::Failed) |
216 1 => value!(AnnounceStatus::Found) |
217 2 => value!(AnnounceStatus::Announced)
218 ));
219}
220
221impl ToBytes for AnnounceStatus {
222 fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
223 gen_be_u8!(buf, *self as u8)
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 const ONION_RETURN_1_PAYLOAD_SIZE: usize = ONION_RETURN_1_SIZE - secretbox::NONCEBYTES;
232
233 encode_decode_test!(
234 tox_crypto::crypto_init().unwrap(),
235 onion_return_encode_decode,
236 OnionReturn {
237 nonce: secretbox::gen_nonce(),
238 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
239 }
240 );
241
242 encode_decode_test!(
243 tox_crypto::crypto_init().unwrap(),
244 announce_status_failed,
245 AnnounceStatus::Failed
246 );
247
248 encode_decode_test!(
249 tox_crypto::crypto_init().unwrap(),
250 announce_status_found,
251 AnnounceStatus::Found
252 );
253
254 encode_decode_test!(
255 tox_crypto::crypto_init().unwrap(),
256 announce_status_accounced,
257 AnnounceStatus::Announced
258 );
259
260 #[test]
261 fn onion_return_encrypt_decrypt() {
262 crypto_init().unwrap();
263 let alice_symmetric_key = secretbox::gen_key();
264 let bob_symmetric_key = secretbox::gen_key();
265 let ip_port_1 = IpPort {
267 protocol: ProtocolType::UDP,
268 ip_addr: "5.6.7.8".parse().unwrap(),
269 port: 12345
270 };
271 let onion_return_1 = OnionReturn::new(&alice_symmetric_key, &ip_port_1, None);
272 let ip_port_2 = IpPort {
274 protocol: ProtocolType::UDP,
275 ip_addr: "7.8.5.6".parse().unwrap(),
276 port: 54321
277 };
278 let onion_return_2 = OnionReturn::new(&bob_symmetric_key, &ip_port_2, Some(&onion_return_1));
279 let (decrypted_ip_port_2, decrypted_onion_return_1) = onion_return_2.get_payload(&bob_symmetric_key).unwrap();
281 assert_eq!(decrypted_ip_port_2, ip_port_2);
282 assert_eq!(decrypted_onion_return_1.unwrap(), onion_return_1);
283 let (decrypted_ip_port_1, none) = onion_return_1.get_payload(&alice_symmetric_key).unwrap();
285 assert_eq!(decrypted_ip_port_1, ip_port_1);
286 assert!(none.is_none());
287 }
288
289 #[test]
290 fn onion_return_encrypt_decrypt_invalid_key() {
291 crypto_init().unwrap();
292 let alice_symmetric_key = secretbox::gen_key();
293 let bob_symmetric_key = secretbox::gen_key();
294 let eve_symmetric_key = secretbox::gen_key();
295 let ip_port_1 = IpPort {
297 protocol: ProtocolType::UDP,
298 ip_addr: "5.6.7.8".parse().unwrap(),
299 port: 12345
300 };
301 let onion_return_1 = OnionReturn::new(&alice_symmetric_key, &ip_port_1, None);
302 let ip_port_2 = IpPort {
304 protocol: ProtocolType::UDP,
305 ip_addr: "7.8.5.6".parse().unwrap(),
306 port: 54321
307 };
308 let onion_return_2 = OnionReturn::new(&bob_symmetric_key, &ip_port_2, Some(&onion_return_1));
309 assert!(onion_return_1.get_payload(&eve_symmetric_key).is_err());
311 assert!(onion_return_2.get_payload(&eve_symmetric_key).is_err());
312 }
313
314 #[test]
315 fn onion_return_decrypt_invalid() {
316 crypto_init().unwrap();
317 let symmetric_key = secretbox::gen_key();
318 let nonce = secretbox::gen_nonce();
319 let invalid_payload = [42; 123];
321 let invalid_payload_encoded = secretbox::seal(&invalid_payload, &nonce, &symmetric_key);
322 let invalid_onion_return = OnionReturn {
323 nonce,
324 payload: invalid_payload_encoded
325 };
326 assert!(invalid_onion_return.get_payload(&symmetric_key).is_err());
327 let invalid_payload = [];
329 let invalid_payload_encoded = secretbox::seal(&invalid_payload, &nonce, &symmetric_key);
330 let invalid_onion_return = OnionReturn {
331 nonce,
332 payload: invalid_payload_encoded
333 };
334 assert!(invalid_onion_return.get_payload(&symmetric_key).is_err());
335 }
336}