1use super::*;
5
6use tox_binary_io::*;
7use tox_crypto::*;
8use crate::dht::*;
9
10use nom::{
11 many0,
12 number::complete::le_u64,
13 combinator::{rest, rest_len},
14};
15
16#[derive(Clone, Debug, Eq, PartialEq)]
35pub struct OnionAnnounceResponse {
36 pub sendback_data: u64,
38 pub nonce: Nonce,
40 pub payload: Vec<u8>
42}
43
44impl FromBytes for OnionAnnounceResponse {
45 named!(from_bytes<OnionAnnounceResponse>, do_parse!(
46 verify!(rest_len, |len| *len <= ONION_MAX_PACKET_SIZE) >>
47 tag!(&[0x84][..]) >>
48 sendback_data: le_u64 >>
49 nonce: call!(Nonce::from_bytes) >>
50 payload: rest >>
51 (OnionAnnounceResponse {
52 sendback_data,
53 nonce,
54 payload: payload.to_vec()
55 })
56 ));
57}
58
59impl ToBytes for OnionAnnounceResponse {
60 fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
61 do_gen!(buf,
62 gen_be_u8!(0x84) >>
63 gen_le_u64!(self.sendback_data) >>
64 gen_slice!(self.nonce.as_ref()) >>
65 gen_slice!(self.payload.as_slice()) >>
66 gen_len_limit(ONION_MAX_PACKET_SIZE)
67 )
68 }
69}
70
71impl OnionAnnounceResponse {
72 pub fn new(shared_secret: &PrecomputedKey, sendback_data: u64, payload: &OnionAnnounceResponsePayload) -> OnionAnnounceResponse {
74 let nonce = gen_nonce();
75 let mut buf = [0; ONION_MAX_PACKET_SIZE];
76 let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
77 let payload = seal_precomputed(&buf[..size], &nonce, shared_secret);
78
79 OnionAnnounceResponse { sendback_data, nonce, payload }
80 }
81
82 pub fn get_payload(&self, shared_secret: &PrecomputedKey) -> Result<OnionAnnounceResponsePayload, GetPayloadError> {
90 let decrypted = open_precomputed(&self.payload, &self.nonce, shared_secret)
91 .map_err(|()| {
92 GetPayloadError::decrypt()
93 })?;
94 match OnionAnnounceResponsePayload::from_bytes(&decrypted) {
95 Err(error) => {
96 Err(GetPayloadError::deserialize(error, decrypted.clone()))
97 },
98 Ok((_, inner)) => {
99 Ok(inner)
100 }
101 }
102 }
103}
104
105#[derive(Clone, Debug, Eq, PartialEq)]
128pub struct OnionAnnounceResponsePayload {
129 pub announce_status: AnnounceStatus,
132 pub ping_id_or_pk: sha256::Digest,
134 pub nodes: Vec<PackedNode>
136}
137
138impl FromBytes for OnionAnnounceResponsePayload {
139 named!(from_bytes<OnionAnnounceResponsePayload>, do_parse!(
140 announce_status: call!(AnnounceStatus::from_bytes) >>
141 ping_id_or_pk: call!(sha256::Digest::from_bytes) >>
142 nodes: many0!(PackedNode::from_bytes) >>
143 _len: verify!(value!(nodes.len()), |len| *len <= 4 as usize) >>
144 eof!() >>
145 (OnionAnnounceResponsePayload {
146 announce_status,
147 ping_id_or_pk,
148 nodes
149 })
150 ));
151}
152
153impl ToBytes for OnionAnnounceResponsePayload {
154 fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
155 do_gen!(buf,
156 gen_call!(|buf, announce_status| AnnounceStatus::to_bytes(announce_status, buf), &self.announce_status) >>
157 gen_slice!(self.ping_id_or_pk.as_ref()) >>
158 gen_cond!(
159 self.nodes.len() <= 4,
160 gen_many_ref!(&self.nodes, |buf, node| PackedNode::to_bytes(node, buf))
161 )
162 )
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 use std::net::SocketAddr;
171
172 encode_decode_test!(
173 tox_crypto::crypto_init().unwrap(),
174 onion_announce_response_encode_decode,
175 OnionAnnounceResponse {
176 sendback_data: 12345,
177 nonce: gen_nonce(),
178 payload: vec![42; 123]
179 }
180 );
181
182 encode_decode_test!(
183 tox_crypto::crypto_init().unwrap(),
184 onion_announce_response_payload_encode_decode,
185 OnionAnnounceResponsePayload {
186 announce_status: AnnounceStatus::Found,
187 ping_id_or_pk: sha256::hash(&[1, 2, 3]),
188 nodes: vec![
189 PackedNode::new(SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
190 ]
191 }
192 );
193
194 #[test]
195 fn onion_announce_response_payload_encrypt_decrypt() {
196 crypto_init().unwrap();
197 let (_alice_pk, alice_sk) = gen_keypair();
198 let (bob_pk, _bob_sk) = gen_keypair();
199 let shared_secret = encrypt_precompute(&bob_pk, &alice_sk);
200 let payload = OnionAnnounceResponsePayload {
201 announce_status: AnnounceStatus::Found,
202 ping_id_or_pk: sha256::hash(&[1, 2, 3]),
203 nodes: vec![
204 PackedNode::new(SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
205 ]
206 };
207 let onion_packet = OnionAnnounceResponse::new(&shared_secret, 12345, &payload);
209 let decoded_payload = onion_packet.get_payload(&shared_secret).unwrap();
211 assert_eq!(decoded_payload, payload);
213 }
214
215 #[test]
216 fn onion_announce_response_payload_encrypt_decrypt_invalid_key() {
217 crypto_init().unwrap();
218 let (_alice_pk, alice_sk) = gen_keypair();
219 let (bob_pk, _bob_sk) = gen_keypair();
220 let (_eve_pk, eve_sk) = gen_keypair();
221 let shared_secret = encrypt_precompute(&bob_pk, &alice_sk);
222 let payload = OnionAnnounceResponsePayload {
223 announce_status: AnnounceStatus::Found,
224 ping_id_or_pk: sha256::hash(&[1, 2, 3]),
225 nodes: vec![
226 PackedNode::new(SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
227 ]
228 };
229 let onion_packet = OnionAnnounceResponse::new(&shared_secret, 12345, &payload);
231 let eve_shared_secret = encrypt_precompute(&bob_pk, &eve_sk);
233 let decoded_payload = onion_packet.get_payload(&eve_shared_secret);
234 assert!(decoded_payload.is_err());
235 }
236
237 #[test]
238 fn onion_announce_response_decrypt_invalid() {
239 crypto_init().unwrap();
240 let (_alice_pk, alice_sk) = gen_keypair();
241 let (bob_pk, _bob_sk) = gen_keypair();
242 let shared_secret = precompute(&bob_pk, &alice_sk);
243 let nonce = gen_nonce();
244 let invalid_payload = [42; 123];
246 let invalid_payload_encoded = seal_precomputed(&invalid_payload, &nonce, &shared_secret);
247 let invalid_onion_announce_response = OnionAnnounceResponse {
248 sendback_data: 12345,
249 nonce,
250 payload: invalid_payload_encoded
251 };
252 assert!(invalid_onion_announce_response.get_payload(&shared_secret).is_err());
253 let invalid_payload = [];
255 let invalid_payload_encoded = seal_precomputed(&invalid_payload, &nonce, &shared_secret);
256 let invalid_onion_announce_response = OnionAnnounceResponse {
257 sendback_data: 12345,
258 nonce,
259 payload: invalid_payload_encoded
260 };
261 assert!(invalid_onion_announce_response.get_payload(&shared_secret).is_err());
262 }
263}