1use super::{
24 crypto::*,
25 delay::Delay,
26 packet::*,
27 target::{MixnodeIndex, Target},
28};
29use arrayref::{array_mut_ref, array_refs, mut_array_refs};
30use arrayvec::ArrayVec;
31use rand::{CryptoRng, Rng};
32
33fn mut_arr_at<T, const N: usize>(slice: &mut [T], offset: usize) -> &mut [T; N] {
34 (&mut slice[offset..offset + N])
35 .try_into()
36 .expect("Slice length is fixed and matches array length")
37}
38
39enum PacketKind<'a> {
40 Request,
41 Reply(&'a SurbId),
42 Cover(Option<&'a CoverId>),
43}
44
45fn build_header(
49 header: &mut Header,
50 kx_shared_secrets: &mut ArrayVec<SharedSecret, MAX_HOPS>,
51 rng: &mut (impl Rng + CryptoRng),
52 targets: &[Target],
53 their_kx_publics: &[KxPublic],
54 kind: PacketKind,
55) -> Delay {
56 debug_assert_eq!(targets.len() + 1, their_kx_publics.len());
57 debug_assert!(their_kx_publics.len() <= MAX_HOPS);
58
59 let (kx_public, mac_plus_actions) =
60 mut_array_refs![header, KX_PUBLIC_SIZE, MAC_SIZE + ACTIONS_SIZE];
61
62 gen_kx_public_and_shared_secrets(kx_public, kx_shared_secrets, rng, their_kx_publics);
63
64 let actions = array_mut_ref![mac_plus_actions, MAC_SIZE, ACTIONS_SIZE];
66 let mut offset = 0;
67
68 let mut total_delay = Delay::zero();
70
71 struct Hop {
74 mac_key: MacKey,
75 keystream: [u8; ACTIONS_SIZE + MAX_ACTIONS_PAD_SIZE],
76 start_offset: u16, }
78 let mut hops: ArrayVec<Hop, { MAX_HOPS - 1 }> = ArrayVec::new();
79
80 let mut pad = [0; ACTIONS_SIZE - RAW_ACTION_SIZE];
83
84 for (target, kx_shared_secret) in targets.iter().zip(kx_shared_secrets.iter()) {
86 let start_offset = offset;
88 offset += RAW_ACTION_SIZE;
89 let raw_action = match target {
90 Target::MixnodeIndex(mixnode_index) => mixnode_index.get(),
91 Target::PeerId(peer_id) => {
92 *mut_arr_at(actions, offset) = *peer_id;
93 offset += PEER_ID_SIZE;
94 RAW_ACTION_FORWARD_TO_PEER_ID
95 },
96 };
97 *mut_arr_at(actions, start_offset) = raw_action.to_le_bytes();
98
99 offset += MAC_SIZE;
102
103 let sds = SmallDerivedSecrets::new(kx_shared_secret);
104
105 total_delay += Delay::exp(sds.delay_seed());
106
107 hops.push(Hop {
108 mac_key: *sds.mac_key(),
109 keystream: [0; ACTIONS_SIZE + MAX_ACTIONS_PAD_SIZE],
110 start_offset: start_offset as u16,
111 });
112 let keystream = &mut hops.last_mut().expect("Just pushed, so not empty").keystream;
113 apply_actions_encryption_keystream(keystream, sds.actions_encryption_key());
114
115 apply_keystream(&mut pad[..offset], &keystream[ACTIONS_SIZE - start_offset..]);
118 }
119
120 {
122 let start_offset = offset;
124 offset += RAW_ACTION_SIZE;
125 let raw_action = match kind {
126 PacketKind::Request => RAW_ACTION_DELIVER_REQUEST,
127 PacketKind::Reply(surb_id) => {
128 *mut_arr_at(actions, offset) = *surb_id;
129 offset += SURB_ID_SIZE;
130 RAW_ACTION_DELIVER_REPLY
131 },
132 PacketKind::Cover(None) => RAW_ACTION_DELIVER_COVER,
133 PacketKind::Cover(Some(cover_id)) => {
134 *mut_arr_at(actions, offset) = *cover_id;
135 offset += COVER_ID_SIZE;
136 RAW_ACTION_DELIVER_COVER_WITH_ID
137 },
138 };
139 *mut_arr_at(actions, start_offset) = raw_action.to_le_bytes();
140
141 rng.fill_bytes(&mut actions[offset..]);
144
145 let sds =
146 SmallDerivedSecrets::new(kx_shared_secrets.last().expect("There is at least one hop"));
147
148 apply_actions_encryption_keystream(
153 &mut actions[start_offset..],
154 sds.actions_encryption_key(),
155 );
156
157 *mut_arr_at(mac_plus_actions, start_offset) =
160 compute_mac(&actions[start_offset..], &pad[..start_offset], sds.mac_key());
161 }
162
163 for hop in hops.iter().rev() {
165 let start_offset = hop.start_offset as usize;
166
167 apply_keystream(&mut mac_plus_actions[MAC_SIZE + start_offset..], &hop.keystream);
169 apply_keystream(&mut pad[..start_offset], &hop.keystream[ACTIONS_SIZE - start_offset..]);
170
171 *mut_arr_at(mac_plus_actions, start_offset) = compute_mac(
174 &mac_plus_actions[MAC_SIZE + start_offset..],
175 &pad[..start_offset],
176 &hop.mac_key,
177 );
178 }
179
180 total_delay
181}
182
183pub fn mut_payload_data(packet: &mut Packet) -> &mut PayloadData {
187 array_mut_ref![packet, HEADER_SIZE, PAYLOAD_DATA_SIZE]
188}
189
190pub fn complete_request_packet(
195 packet: &mut Packet,
196 rng: &mut (impl Rng + CryptoRng),
197 targets: &[Target],
198 their_kx_publics: &[KxPublic],
199) -> Delay {
200 debug_assert_eq!(targets.len() + 1, their_kx_publics.len());
201 debug_assert!(their_kx_publics.len() <= MAX_HOPS);
202
203 let (header, payload) = mut_array_refs![packet, HEADER_SIZE, PAYLOAD_SIZE];
204
205 let mut kx_shared_secrets = ArrayVec::new();
207 let total_delay = build_header(
208 header,
209 &mut kx_shared_secrets,
210 rng,
211 targets,
212 their_kx_publics,
213 PacketKind::Request,
214 );
215
216 *array_mut_ref![payload, PAYLOAD_DATA_SIZE, PAYLOAD_TAG_SIZE] = PAYLOAD_TAG;
218
219 for kx_shared_secret in kx_shared_secrets.iter().rev() {
221 encrypt_payload(payload, &derive_payload_encryption_key(kx_shared_secret));
222 }
223
224 total_delay
225}
226
227pub const SURB_SIZE: usize = RAW_MIXNODE_INDEX_SIZE + HEADER_SIZE + SHARED_SECRET_SIZE;
229pub type Surb = [u8; SURB_SIZE];
231
232pub type SurbPayloadEncryptionKeys = ArrayVec<PayloadEncryptionKey, MAX_HOPS>;
233
234pub fn build_surb(
241 surb: &mut Surb,
242 payload_encryption_keys: &mut SurbPayloadEncryptionKeys,
243 rng: &mut (impl Rng + CryptoRng),
244 first_mixnode_index: MixnodeIndex,
245 targets: &[Target],
246 their_kx_publics: &[KxPublic],
247 id: &SurbId,
248) -> Delay {
249 debug_assert_eq!(targets.len() + 1, their_kx_publics.len());
250 debug_assert!(their_kx_publics.len() <= MAX_HOPS);
251
252 let (raw_first_mixnode_index, header, shared_secret) =
253 mut_array_refs![surb, RAW_MIXNODE_INDEX_SIZE, HEADER_SIZE, SHARED_SECRET_SIZE];
254
255 *raw_first_mixnode_index = first_mixnode_index.get().to_le_bytes();
256
257 let mut kx_shared_secrets = ArrayVec::new();
259 let total_delay = build_header(
260 header,
261 &mut kx_shared_secrets,
262 rng,
263 targets,
264 their_kx_publics,
265 PacketKind::Reply(id),
266 );
267
268 rng.fill_bytes(shared_secret);
274 payload_encryption_keys.push(derive_payload_encryption_key(shared_secret));
275 kx_shared_secrets.pop(); for kx_shared_secret in &kx_shared_secrets {
277 payload_encryption_keys.push(derive_payload_encryption_key(kx_shared_secret));
278 }
279
280 total_delay
281}
282
283pub fn complete_reply_packet(packet: &mut Packet, surb: &Surb) -> Option<MixnodeIndex> {
288 let (header, payload) = mut_array_refs![packet, HEADER_SIZE, PAYLOAD_SIZE];
289 let (raw_first_mixnode_index, surb_header, shared_secret) =
290 array_refs![surb, RAW_MIXNODE_INDEX_SIZE, HEADER_SIZE, SHARED_SECRET_SIZE];
291
292 *header = *surb_header;
295
296 *array_mut_ref![payload, PAYLOAD_DATA_SIZE, PAYLOAD_TAG_SIZE] = PAYLOAD_TAG;
298
299 decrypt_payload(payload, &derive_payload_encryption_key(shared_secret));
301
302 let raw_first_mixnode_index = RawMixnodeIndex::from_le_bytes(*raw_first_mixnode_index);
304 raw_first_mixnode_index.try_into().ok()
305}
306
307pub fn build_cover_packet(
311 packet: &mut Packet,
312 rng: &mut (impl Rng + CryptoRng),
313 targets: &[Target],
314 their_kx_publics: &[KxPublic],
315 id: Option<&CoverId>,
316) -> Delay {
317 debug_assert_eq!(targets.len() + 1, their_kx_publics.len());
318 debug_assert!(their_kx_publics.len() <= MAX_HOPS);
319
320 let (header, payload) = mut_array_refs![packet, HEADER_SIZE, PAYLOAD_SIZE];
321
322 let mut kx_shared_secrets = ArrayVec::new();
324 let total_delay = build_header(
325 header,
326 &mut kx_shared_secrets,
327 rng,
328 targets,
329 their_kx_publics,
330 PacketKind::Cover(id),
331 );
332
333 rng.fill_bytes(payload);
336
337 total_delay
338}