1use super::*;
5
6use tox_binary_io::*;
7use crate::dht::*;
8
9use nom::{
10 combinator::{rest, rest_len},
11 bytes::complete::take
12};
13
14const ONION_REQUEST_1_MIN_PAYLOAD_SIZE: usize = SIZE_IPPORT + MACBYTES;
16
17#[derive(Clone, Debug, Eq, PartialEq)]
35pub struct OnionRequest1 {
36 pub nonce: Nonce,
38 pub temporary_pk: PublicKey,
40 pub payload: Vec<u8>,
42 pub onion_return: OnionReturn
44}
45
46impl FromBytes for OnionRequest1 {
47 named!(from_bytes<OnionRequest1>, do_parse!(
48 verify!(rest_len, |len| *len <= ONION_MAX_PACKET_SIZE) >>
49 tag!(&[0x81][..]) >>
50 nonce: call!(Nonce::from_bytes) >>
51 temporary_pk: call!(PublicKey::from_bytes) >>
52 rest_len: verify!(rest_len, |rest_len| *rest_len >= ONION_REQUEST_1_MIN_PAYLOAD_SIZE + ONION_RETURN_1_SIZE) >>
53 payload: call!(take(rest_len - ONION_RETURN_1_SIZE)) >>
54 onion_return: call!(OnionReturn::from_bytes) >>
55 (OnionRequest1 {
56 nonce,
57 temporary_pk,
58 payload: payload.to_vec(),
59 onion_return
60 })
61 ));
62}
63
64impl ToBytes for OnionRequest1 {
65 fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
66 do_gen!(buf,
67 gen_cond!(
68 self.payload.len() < ONION_REQUEST_1_MIN_PAYLOAD_SIZE,
69 |buf| gen_error(buf, 0)
70 ) >>
71 gen_be_u8!(0x81) >>
72 gen_slice!(self.nonce.as_ref()) >>
73 gen_slice!(self.temporary_pk.as_ref()) >>
74 gen_slice!(self.payload.as_slice()) >>
75 gen_call!(|buf, onion_return| OnionReturn::to_bytes(onion_return, buf), &self.onion_return) >>
76 gen_len_limit(ONION_MAX_PACKET_SIZE)
77 )
78 }
79}
80
81impl OnionRequest1 {
82 pub fn new(shared_secret: &PrecomputedKey, temporary_pk: &PublicKey, payload: &OnionRequest1Payload, onion_return: OnionReturn) -> OnionRequest1 {
84 let nonce = gen_nonce();
85 let mut buf = [0; ONION_MAX_PACKET_SIZE];
86 let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
87 let payload = seal_precomputed(&buf[..size], &nonce, shared_secret);
88
89 OnionRequest1 { nonce, temporary_pk: *temporary_pk, payload, onion_return }
90 }
91
92 pub fn get_payload(&self, shared_secret: &PrecomputedKey) -> Result<OnionRequest1Payload, GetPayloadError> {
100 let decrypted = open_precomputed(&self.payload, &self.nonce, shared_secret)
101 .map_err(|()| {
102 GetPayloadError::decrypt()
103 })?;
104 match OnionRequest1Payload::from_bytes(&decrypted) {
105 Err(error) => {
106 Err(GetPayloadError::deserialize(error, decrypted.clone()))
107 },
108 Ok((_, inner)) => {
109 Ok(inner)
110 }
111 }
112 }
113}
114
115#[derive(Clone, Debug, Eq, PartialEq)]
131pub struct OnionRequest1Payload {
132 pub ip_port: IpPort,
134 pub temporary_pk: PublicKey,
136 pub inner: Vec<u8>
138}
139
140impl FromBytes for OnionRequest1Payload {
141 named!(from_bytes<OnionRequest1Payload>, do_parse!(
142 ip_port: call!(IpPort::from_udp_bytes, IpPortPadding::WithPadding) >>
143 temporary_pk: call!(PublicKey::from_bytes) >>
144 inner: rest >>
145 (OnionRequest1Payload {
146 ip_port,
147 temporary_pk,
148 inner: inner.to_vec()
149 })
150 ));
151}
152
153impl ToBytes for OnionRequest1Payload {
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, ip_port| IpPort::to_udp_bytes(ip_port, buf, IpPortPadding::WithPadding), &self.ip_port) >>
157 gen_slice!(self.temporary_pk.as_ref()) >>
158 gen_slice!(self.inner.as_slice())
159 )
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 const ONION_RETURN_1_PAYLOAD_SIZE: usize = ONION_RETURN_1_SIZE - secretbox::NONCEBYTES;
168
169 encode_decode_test!(
170 tox_crypto::crypto_init().unwrap(),
171 onion_request_1_encode_decode,
172 OnionRequest1 {
173 nonce: gen_nonce(),
174 temporary_pk: gen_keypair().0,
175 payload: vec![42; ONION_REQUEST_1_MIN_PAYLOAD_SIZE],
176 onion_return: OnionReturn {
177 nonce: secretbox::gen_nonce(),
178 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
179 }
180 }
181 );
182
183 encode_decode_test!(
184 tox_crypto::crypto_init().unwrap(),
185 onion_request_1_payload_encode_decode,
186 OnionRequest1Payload {
187 ip_port: IpPort {
188 protocol: ProtocolType::UDP,
189 ip_addr: "5.6.7.8".parse().unwrap(),
190 port: 12345
191 },
192 temporary_pk: gen_keypair().0,
193 inner: vec![42; ONION_REQUEST_1_MIN_PAYLOAD_SIZE]
194 }
195 );
196
197 #[test]
198 fn onion_request_1_payload_encrypt_decrypt() {
199 crypto_init().unwrap();
200 let (alice_pk, alice_sk) = gen_keypair();
201 let (bob_pk, _bob_sk) = gen_keypair();
202 let shared_secret = encrypt_precompute(&bob_pk, &alice_sk);
203 let payload = OnionRequest1Payload {
204 ip_port: IpPort {
205 protocol: ProtocolType::UDP,
206 ip_addr: "5.6.7.8".parse().unwrap(),
207 port: 12345
208 },
209 temporary_pk: gen_keypair().0,
210 inner: vec![42; ONION_REQUEST_1_MIN_PAYLOAD_SIZE]
211 };
212 let onion_return = OnionReturn {
213 nonce: secretbox::gen_nonce(),
214 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
215 };
216 let onion_packet = OnionRequest1::new(&shared_secret, &alice_pk, &payload, onion_return);
218 let decoded_payload = onion_packet.get_payload(&shared_secret).unwrap();
220 assert_eq!(decoded_payload, payload);
222 }
223
224 #[test]
225 fn onion_request_1_payload_encrypt_decrypt_invalid_key() {
226 crypto_init().unwrap();
227 let (alice_pk, alice_sk) = gen_keypair();
228 let (bob_pk, _bob_sk) = gen_keypair();
229 let (_eve_pk, eve_sk) = gen_keypair();
230 let shared_secret = encrypt_precompute(&bob_pk, &alice_sk);
231 let payload = OnionRequest1Payload {
232 ip_port: IpPort {
233 protocol: ProtocolType::UDP,
234 ip_addr: "5.6.7.8".parse().unwrap(),
235 port: 12345
236 },
237 temporary_pk: gen_keypair().0,
238 inner: vec![42; ONION_REQUEST_1_MIN_PAYLOAD_SIZE]
239 };
240 let onion_return = OnionReturn {
241 nonce: secretbox::gen_nonce(),
242 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
243 };
244 let onion_packet = OnionRequest1::new(&shared_secret, &alice_pk, &payload, onion_return);
246 let eve_shared_secret = encrypt_precompute(&bob_pk, &eve_sk);
248 let decoded_payload = onion_packet.get_payload(&eve_shared_secret);
249 assert!(decoded_payload.is_err());
250 }
251
252 #[test]
253 fn onion_request_1_decrypt_invalid() {
254 crypto_init().unwrap();
255 let (_alice_pk, alice_sk) = gen_keypair();
256 let (bob_pk, _bob_sk) = gen_keypair();
257 let shared_secret = precompute(&bob_pk, &alice_sk);
258 let nonce = gen_nonce();
259 let temporary_pk = gen_keypair().0;
260 let invalid_payload = [42; ONION_REQUEST_1_MIN_PAYLOAD_SIZE];
262 let invalid_payload_encoded = seal_precomputed(&invalid_payload, &nonce, &shared_secret);
263 let invalid_onion_request_1 = OnionRequest1 {
264 nonce,
265 temporary_pk,
266 payload: invalid_payload_encoded,
267 onion_return: OnionReturn {
268 nonce: secretbox::gen_nonce(),
269 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
270 }
271 };
272 assert!(invalid_onion_request_1.get_payload(&shared_secret).is_err());
273 let invalid_payload = [];
275 let invalid_payload_encoded = seal_precomputed(&invalid_payload, &nonce, &shared_secret);
276 let invalid_onion_request_1 = OnionRequest1 {
277 nonce,
278 temporary_pk,
279 payload: invalid_payload_encoded,
280 onion_return: OnionReturn {
281 nonce: secretbox::gen_nonce(),
282 payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
283 }
284 };
285 assert!(invalid_onion_request_1.get_payload(&shared_secret).is_err());
286 }
287}