tox_core/onion/client/
onion_path.rs

1//! Onion path definition.
2
3use std::net::SocketAddr;
4
5use tox_binary_io::*;
6use tox_crypto::*;
7use tox_packet::dht::packed_node::*;
8use tox_packet::ip_port::*;
9use tox_packet::onion::*;
10use tox_packet::relay::OnionRequest;
11
12/// Whether the first node of onion path is a TCP relay or DHT node.
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum OnionPathType {
15    /// The first node of onion path is a TCP relay.
16    TCP,
17    /// The first node of onion path is a DHT node.
18    UDP
19}
20
21/// Onion path is identified by 3 public keys of nodes it consists of.
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub struct OnionPathId {
24    /// Public keys of nodes the path consists of.
25    pub keys: [PublicKey; 3],
26    /// Whether the first node is a TCP relay or DHT node.
27    pub path_type: OnionPathType,
28}
29
30/// Node for onion path.
31#[derive(Clone, Debug, Eq, PartialEq)]
32pub struct OnionPathNode {
33    /// Node's `PublicKey`.
34    pub public_key: PublicKey,
35    /// Temporary `PublicKey` for this node.
36    pub temporary_public_key: PublicKey,
37    /// Temporary `PrecomputedKey` to encrypt packets for this node.
38    pub temporary_precomputed_key: PrecomputedKey,
39    /// Node's IP address.
40    pub saddr: SocketAddr,
41}
42
43impl OnionPathNode {
44    /// Create new `OnionPathNode` from `PackedNode` generating random key pair
45    /// to encrypt packets intended for this node.
46    pub fn new(node: PackedNode) -> Self {
47        let (temporary_public_key, temporary_secret_key) = gen_keypair();
48        let temporary_precomputed_key = precompute(&node.pk, &temporary_secret_key);
49        OnionPathNode {
50            public_key: node.pk,
51            temporary_public_key,
52            temporary_precomputed_key,
53            saddr: node.saddr,
54        }
55    }
56}
57
58/// Onion path that consists of 3 random nodes.
59#[derive(Clone, Debug, Eq, PartialEq)]
60pub struct OnionPath {
61    /// Random path nodes.
62    pub nodes: [OnionPathNode; 3],
63    /// Whether the first node is a TCP relay or DHT node.
64    pub path_type: OnionPathType,
65}
66
67impl OnionPath {
68    /// Create new `OnionPath` from 3 `PackedNode`s generating random key pair
69    /// for each node.
70    pub fn new(nodes: [PackedNode; 3], path_type: OnionPathType) -> Self {
71        OnionPath {
72            nodes: [
73                OnionPathNode::new(nodes[0]),
74                OnionPathNode::new(nodes[1]),
75                OnionPathNode::new(nodes[2]),
76            ],
77            path_type,
78        }
79    }
80
81    /// Array of 3 public keys of nodes the path consists of.
82    pub fn id(&self) -> OnionPathId {
83        let keys = [
84            self.nodes[0].public_key,
85            self.nodes[1].public_key,
86            self.nodes[2].public_key,
87        ];
88        OnionPathId {
89            keys,
90            path_type: self.path_type,
91        }
92    }
93
94    /// Create `OnionRequest0` packet from `InnerOnionRequest` that should be
95    /// sent through this path.
96    pub fn create_udp_onion_request(&self, destination: SocketAddr, inner_onion_request: InnerOnionRequest) -> OnionRequest0 {
97        let nonce = gen_nonce();
98        let mut buf = [0; ONION_MAX_PACKET_SIZE];
99
100        let payload = OnionRequest2Payload {
101            ip_port: IpPort::from_udp_saddr(destination),
102            inner: inner_onion_request,
103        };
104        let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
105        let encrypted = seal_precomputed(&buf[..size], &nonce, &self.nodes[2].temporary_precomputed_key);
106
107        let payload = OnionRequest1Payload {
108            ip_port: IpPort::from_udp_saddr(self.nodes[2].saddr),
109            temporary_pk: self.nodes[2].temporary_public_key,
110            inner: encrypted,
111        };
112        let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
113        let encrypted = seal_precomputed(&buf[..size], &nonce, &self.nodes[1].temporary_precomputed_key);
114
115        let payload = OnionRequest0Payload {
116            ip_port: IpPort::from_udp_saddr(self.nodes[1].saddr),
117            temporary_pk: self.nodes[1].temporary_public_key,
118            inner: encrypted,
119        };
120        let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
121        let encrypted = seal_precomputed(&buf[..size], &nonce, &self.nodes[0].temporary_precomputed_key);
122
123        OnionRequest0 {
124            nonce,
125            temporary_pk: self.nodes[0].temporary_public_key,
126            payload: encrypted
127        }
128    }
129
130    /// Create `OnionRequest` packet from `InnerOnionRequest` that should be
131    /// sent through this path.
132    pub fn create_tcp_onion_request(&self, destination: SocketAddr, inner_onion_request: InnerOnionRequest) -> OnionRequest {
133        let nonce = gen_nonce();
134        let mut buf = [0; ONION_MAX_PACKET_SIZE];
135
136        let payload = OnionRequest2Payload {
137            ip_port: IpPort::from_udp_saddr(destination),
138            inner: inner_onion_request,
139        };
140        let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
141        let encrypted = seal_precomputed(&buf[..size], &nonce, &self.nodes[2].temporary_precomputed_key);
142
143        let payload = OnionRequest1Payload {
144            ip_port: IpPort::from_udp_saddr(self.nodes[2].saddr),
145            temporary_pk: self.nodes[2].temporary_public_key,
146            inner: encrypted,
147        };
148        let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
149        let encrypted = seal_precomputed(&buf[..size], &nonce, &self.nodes[1].temporary_precomputed_key);
150
151        OnionRequest {
152            nonce,
153            ip_port: IpPort::from_udp_saddr(self.nodes[1].saddr),
154            temporary_pk: self.nodes[1].temporary_public_key,
155            payload: encrypted,
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn onion_path_node_new() {
166        let saddr = "127.0.0.1:12345".parse().unwrap();
167        let (pk, sk) = gen_keypair();
168        let node = OnionPathNode::new(PackedNode::new(saddr, &pk));
169        let precomputed = precompute(&node.temporary_public_key, &sk);
170        assert_eq!(node.saddr, saddr);
171        assert_eq!(node.public_key, pk);
172        assert_eq!(node.temporary_precomputed_key, precomputed);
173    }
174
175    #[test]
176    fn onion_path_id() {
177        let saddr_1 = "127.0.0.1:12345".parse().unwrap();
178        let saddr_2 = "127.0.0.1:12346".parse().unwrap();
179        let saddr_3 = "127.0.0.1:12347".parse().unwrap();
180        let pk_1 = gen_keypair().0;
181        let pk_2 = gen_keypair().0;
182        let pk_3 = gen_keypair().0;
183        let path = OnionPath::new([
184            PackedNode::new(saddr_1, &pk_1),
185            PackedNode::new(saddr_2, &pk_2),
186            PackedNode::new(saddr_3, &pk_3),
187        ], OnionPathType::UDP);
188        assert_eq!(path.id(), OnionPathId {
189            keys: [pk_1, pk_2, pk_3],
190            path_type: OnionPathType::UDP,
191        });
192    }
193
194    #[test]
195    fn onion_path_create_udp_onion_request() {
196        let saddr_1 = "127.0.0.1:12345".parse().unwrap();
197        let saddr_2 = "127.0.0.1:12346".parse().unwrap();
198        let saddr_3 = "127.0.0.1:12347".parse().unwrap();
199        let pk_1 = gen_keypair().0;
200        let pk_2 = gen_keypair().0;
201        let pk_3 = gen_keypair().0;
202        let path = OnionPath::new([
203            PackedNode::new(saddr_1, &pk_1),
204            PackedNode::new(saddr_2, &pk_2),
205            PackedNode::new(saddr_3, &pk_3),
206        ], OnionPathType::UDP);
207        let inner_onion_request = InnerOnionRequest::InnerOnionAnnounceRequest(InnerOnionAnnounceRequest {
208            nonce: gen_nonce(),
209            pk: gen_keypair().0,
210            payload: vec![42; 123],
211        });
212        let destination = "127.0.0.1:12348".parse().unwrap();
213        let onion_request = path.create_udp_onion_request(destination, inner_onion_request.clone());
214
215        assert_eq!(onion_request.temporary_pk, path.nodes[0].temporary_public_key);
216        let payload = onion_request.get_payload(&path.nodes[0].temporary_precomputed_key).unwrap();
217        assert_eq!(payload.ip_port, IpPort::from_udp_saddr(saddr_2));
218        assert_eq!(payload.temporary_pk, path.nodes[1].temporary_public_key);
219        let payload = open_precomputed(&payload.inner, &onion_request.nonce, &path.nodes[1].temporary_precomputed_key).unwrap();
220        let payload = OnionRequest1Payload::from_bytes(&payload).unwrap().1;
221        assert_eq!(payload.ip_port, IpPort::from_udp_saddr(saddr_3));
222        assert_eq!(payload.temporary_pk, path.nodes[2].temporary_public_key);
223        let payload = open_precomputed(&payload.inner, &onion_request.nonce, &path.nodes[2].temporary_precomputed_key).unwrap();
224        let payload = OnionRequest2Payload::from_bytes(&payload).unwrap().1;
225        assert_eq!(payload.ip_port, IpPort::from_udp_saddr(destination));
226        assert_eq!(payload.inner, inner_onion_request);
227    }
228
229    #[test]
230    fn onion_path_create_tcp_onion_request() {
231        let saddr_1 = "127.0.0.1:12345".parse().unwrap();
232        let saddr_2 = "127.0.0.1:12346".parse().unwrap();
233        let saddr_3 = "127.0.0.1:12347".parse().unwrap();
234        let pk_1 = gen_keypair().0;
235        let pk_2 = gen_keypair().0;
236        let pk_3 = gen_keypair().0;
237        let path = OnionPath::new([
238            PackedNode::new(saddr_1, &pk_1),
239            PackedNode::new(saddr_2, &pk_2),
240            PackedNode::new(saddr_3, &pk_3),
241        ], OnionPathType::UDP);
242        let inner_onion_request = InnerOnionRequest::InnerOnionAnnounceRequest(InnerOnionAnnounceRequest {
243            nonce: gen_nonce(),
244            pk: gen_keypair().0,
245            payload: vec![42; 123],
246        });
247        let destination = "127.0.0.1:12348".parse().unwrap();
248        let onion_request = path.create_tcp_onion_request(destination, inner_onion_request.clone());
249
250        assert_eq!(onion_request.temporary_pk, path.nodes[1].temporary_public_key);
251        assert_eq!(onion_request.ip_port, IpPort::from_udp_saddr(saddr_2));
252        let payload = open_precomputed(&onion_request.payload, &onion_request.nonce, &path.nodes[1].temporary_precomputed_key).unwrap();
253        let payload = OnionRequest1Payload::from_bytes(&payload).unwrap().1;
254        assert_eq!(payload.ip_port, IpPort::from_udp_saddr(saddr_3));
255        assert_eq!(payload.temporary_pk, path.nodes[2].temporary_public_key);
256        let payload = open_precomputed(&payload.inner, &onion_request.nonce, &path.nodes[2].temporary_precomputed_key).unwrap();
257        let payload = OnionRequest2Payload::from_bytes(&payload).unwrap().1;
258        assert_eq!(payload.ip_port, IpPort::from_udp_saddr(destination));
259        assert_eq!(payload.inner, inner_onion_request);
260    }
261}