1use crate::constants::{
16 DELAY_LENGTH, DESTINATION_ADDRESS_LENGTH, HEADER_INTEGRITY_MAC_SIZE, IDENTIFIER_LENGTH,
17 NODE_ADDRESS_LENGTH, NODE_META_INFO_SIZE, STREAM_CIPHER_OUTPUT_LENGTH, VERSION_LENGTH,
18};
19use crate::crypto;
20use crate::crypto::STREAM_CIPHER_INIT_VECTOR;
21use crate::header::delays::Delay;
22use crate::header::keys::{HeaderIntegrityMacKey, StreamCipherKey};
23use crate::header::mac::HeaderIntegrityMac;
24use crate::header::routing::{
25 EncapsulatedRoutingInformation, RoutingFlag, ENCRYPTED_ROUTING_INFO_SIZE, FINAL_HOP,
26 FORWARD_HOP, TRUNCATED_ROUTING_INFO_SIZE,
27};
28use crate::header::shared_secret::ExpandedSharedSecret;
29use crate::header::{ProcessedHeader, ProcessedHeaderData, SphinxHeader};
30use crate::payload::key::derive_payload_key;
31use crate::route::{DestinationAddressBytes, NodeAddressBytes, SURBIdentifier};
32use crate::utils;
33use crate::version::Version;
34use crate::{Error, ErrorKind, Result};
35use std::fmt;
36use x25519_dalek::PublicKey;
37
38pub const PADDED_ENCRYPTED_ROUTING_INFO_SIZE: usize =
39 ENCRYPTED_ROUTING_INFO_SIZE + NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE;
40
41pub(super) struct RoutingInformation {
43 flag: RoutingFlag,
44 version: Version,
45 node_address: NodeAddressBytes,
47 delay: Delay,
48 header_integrity_mac: HeaderIntegrityMac,
50 next_routing_information: TruncatedRoutingInformation,
52}
53
54impl RoutingInformation {
55 pub(super) fn new(
56 node_address: NodeAddressBytes,
57 delay: Delay,
58 next_encapsulated_routing_information: EncapsulatedRoutingInformation,
59 version: Version,
60 ) -> Self {
61 RoutingInformation {
62 flag: FORWARD_HOP,
63 version,
64 node_address,
65 delay,
66 header_integrity_mac: next_encapsulated_routing_information.integrity_mac,
67 next_routing_information: next_encapsulated_routing_information
68 .enc_routing_information
69 .truncate(),
70 }
71 }
72
73 fn concatenate_components(self) -> Vec<u8> {
74 std::iter::once(self.flag)
75 .chain(self.version.to_bytes().iter().copied())
76 .chain(self.node_address.as_bytes().iter().copied())
77 .chain(self.delay.to_bytes().iter().copied())
78 .chain(self.header_integrity_mac.into_inner())
79 .chain(self.next_routing_information.iter().copied())
80 .collect()
81 }
82
83 pub(super) fn encrypt(self, key: &StreamCipherKey) -> EncryptedRoutingInformation {
84 let routing_info_components = self.concatenate_components();
85 assert_eq!(ENCRYPTED_ROUTING_INFO_SIZE, routing_info_components.len());
86
87 let pseudorandom_bytes = crypto::generate_pseudorandom_bytes(
88 key,
89 &STREAM_CIPHER_INIT_VECTOR,
90 STREAM_CIPHER_OUTPUT_LENGTH,
91 );
92
93 let encrypted_routing_info_vec = utils::bytes::xor(
94 &routing_info_components,
95 &pseudorandom_bytes[..ENCRYPTED_ROUTING_INFO_SIZE],
96 );
97
98 let mut encrypted_routing_info = [0u8; ENCRYPTED_ROUTING_INFO_SIZE];
99 encrypted_routing_info.copy_from_slice(&encrypted_routing_info_vec);
100
101 EncryptedRoutingInformation {
102 value: encrypted_routing_info,
103 }
104 }
105}
106
107#[derive(Clone)]
110pub struct EncryptedRoutingInformation {
111 value: [u8; ENCRYPTED_ROUTING_INFO_SIZE],
112}
113
114impl AsRef<[u8]> for EncryptedRoutingInformation {
115 fn as_ref(&self) -> &[u8] {
116 self.value.as_ref()
117 }
118}
119
120impl fmt::Debug for EncryptedRoutingInformation {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("EncryptedRoutingInformation")
123 .field("value", &self.value)
124 .finish()
125 }
126}
127
128impl EncryptedRoutingInformation {
129 pub fn from_bytes(bytes: [u8; ENCRYPTED_ROUTING_INFO_SIZE]) -> Self {
130 Self { value: bytes }
131 }
132
133 fn truncate(self) -> TruncatedRoutingInformation {
134 let mut truncated_routing_info = [0u8; TRUNCATED_ROUTING_INFO_SIZE];
135 truncated_routing_info.copy_from_slice(&self.value[..TRUNCATED_ROUTING_INFO_SIZE]);
136 truncated_routing_info
137 }
138
139 pub(super) fn encapsulate_with_mac(
140 self,
141 key: &HeaderIntegrityMacKey,
142 ) -> EncapsulatedRoutingInformation {
143 let integrity_mac = HeaderIntegrityMac::compute(key, &self.value);
144 EncapsulatedRoutingInformation {
145 enc_routing_information: self,
146 integrity_mac,
147 }
148 }
149
150 fn add_zero_padding(self) -> PaddedEncryptedRoutingInformation {
151 let zero_bytes = std::iter::repeat_n(0u8, NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE);
152 let padded_enc_routing_info: Vec<u8> =
153 self.value.iter().copied().chain(zero_bytes).collect();
154
155 assert_eq!(
156 PADDED_ENCRYPTED_ROUTING_INFO_SIZE,
157 padded_enc_routing_info.len()
158 );
159 PaddedEncryptedRoutingInformation {
160 value: padded_enc_routing_info,
161 }
162 }
163
164 pub(crate) fn unwrap(
165 self,
166 stream_cipher_key: &StreamCipherKey,
167 ) -> Result<ParsedRawRoutingInformation> {
168 self.add_zero_padding().decrypt(stream_cipher_key).parse()
170 }
171}
172
173pub struct PaddedEncryptedRoutingInformation {
174 value: Vec<u8>,
175}
176
177impl PaddedEncryptedRoutingInformation {
178 pub fn decrypt(self, key: &StreamCipherKey) -> RawRoutingInformation {
179 let pseudorandom_bytes = crypto::generate_pseudorandom_bytes(
180 key,
181 &STREAM_CIPHER_INIT_VECTOR,
182 STREAM_CIPHER_OUTPUT_LENGTH,
183 );
184
185 debug_assert_eq!(self.value.len(), pseudorandom_bytes.len());
186 RawRoutingInformation {
187 value: utils::bytes::xor(&self.value, &pseudorandom_bytes),
188 }
189 }
190}
191
192pub struct RawRoutingInformation {
193 value: Vec<u8>,
194}
195
196pub struct ParsedRawRoutingInformation {
197 pub(crate) version: Version,
198 pub(crate) data: ParsedRawRoutingInformationData,
199}
200
201pub enum ParsedRawRoutingInformationData {
202 ForwardHop {
203 next_hop_address: NodeAddressBytes,
204 delay: Delay,
205 new_routing_information: Box<EncapsulatedRoutingInformation>,
206 },
207 FinalHop {
208 destination: DestinationAddressBytes,
209 identifier: SURBIdentifier,
210 },
211}
212
213impl ParsedRawRoutingInformation {
214 pub(crate) fn into_processed_header(
215 self,
216 shared_secret: PublicKey,
217 expanded_shared_secret: &ExpandedSharedSecret,
218 ) -> ProcessedHeader {
219 let version = self.version;
220 let payload_key = if version.expects_legacy_full_payload_keys() {
221 *expanded_shared_secret.legacy_payload_key()
222 } else {
223 derive_payload_key(expanded_shared_secret.payload_key_seed())
224 };
225
226 match self.data {
227 ParsedRawRoutingInformationData::ForwardHop {
228 next_hop_address,
229 delay,
230 new_routing_information,
231 } => {
232 let new_shared_secret = expanded_shared_secret.blind_shared_secret(shared_secret);
234
235 ProcessedHeader {
236 payload_key,
237 version,
238 data: ProcessedHeaderData::ForwardHop {
239 updated_header: SphinxHeader {
240 shared_secret: new_shared_secret,
241 routing_info: new_routing_information,
242 },
243 next_hop_address,
244 delay,
245 },
246 }
247 }
248 ParsedRawRoutingInformationData::FinalHop {
249 destination,
250 identifier,
251 } => ProcessedHeader {
252 payload_key,
253 version,
254 data: ProcessedHeaderData::FinalHop {
255 destination,
256 identifier,
257 },
258 },
259 }
260 }
261
262 #[deprecated]
263 #[allow(deprecated)]
264 pub(crate) fn legacy_into_processed_header(
265 self,
266 shared_secret: PublicKey,
267 expanded_shared_secret: &ExpandedSharedSecret,
268 ) -> ProcessedHeader {
269 let version = self.version;
271 let payload_key = *expanded_shared_secret.legacy_payload_key();
272
273 match self.data {
274 ParsedRawRoutingInformationData::ForwardHop {
275 next_hop_address,
276 delay,
277 new_routing_information,
278 } => {
279 let new_shared_secret =
281 expanded_shared_secret.legacy_blind_share_secret(shared_secret);
282
283 ProcessedHeader {
284 payload_key,
285 version,
286 data: ProcessedHeaderData::ForwardHop {
287 updated_header: SphinxHeader {
288 shared_secret: new_shared_secret,
289 routing_info: new_routing_information,
290 },
291 next_hop_address,
292 delay,
293 },
294 }
295 }
296 ParsedRawRoutingInformationData::FinalHop {
297 destination,
298 identifier,
299 } => ProcessedHeader {
300 payload_key,
301 version,
302 data: ProcessedHeaderData::FinalHop {
303 destination,
304 identifier,
305 },
306 },
307 }
308 }
309}
310
311impl RawRoutingInformation {
312 pub(crate) fn parse(self) -> Result<ParsedRawRoutingInformation> {
313 debug_assert_eq!(
315 NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE,
316 self.value.len()
317 );
318
319 let flag = self.value[0];
320 match flag {
321 FORWARD_HOP => Ok(self.parse_as_forward_hop()),
322 FINAL_HOP => Ok(self.parse_as_final_hop()),
323 _ => Err(Error::new(
324 ErrorKind::InvalidRouting,
325 format!("tried to parse unknown routing flag: {flag}"),
326 )),
327 }
328 }
329
330 fn parse_as_forward_hop(self) -> ParsedRawRoutingInformation {
332 let mut i = 1;
333
334 let version_ref = &self.value[i..i + VERSION_LENGTH];
335 i += VERSION_LENGTH;
336
337 let mut next_hop_address: [u8; NODE_ADDRESS_LENGTH] = Default::default();
338 next_hop_address.copy_from_slice(&self.value[i..i + NODE_ADDRESS_LENGTH]);
339 i += NODE_ADDRESS_LENGTH;
340
341 let mut delay_bytes: [u8; DELAY_LENGTH] = Default::default();
342 delay_bytes.copy_from_slice(&self.value[i..i + DELAY_LENGTH]);
343 i += DELAY_LENGTH;
344
345 let mut next_hop_integrity_mac: [u8; HEADER_INTEGRITY_MAC_SIZE] = Default::default();
347 next_hop_integrity_mac.copy_from_slice(&self.value[i..i + HEADER_INTEGRITY_MAC_SIZE]);
348 i += HEADER_INTEGRITY_MAC_SIZE;
349
350 let mut next_hop_encrypted_routing_information = [0u8; ENCRYPTED_ROUTING_INFO_SIZE];
352 next_hop_encrypted_routing_information
353 .copy_from_slice(&self.value[i..i + ENCRYPTED_ROUTING_INFO_SIZE]);
354
355 let next_hop_encapsulated_routing_info = EncapsulatedRoutingInformation::encapsulate(
356 EncryptedRoutingInformation::from_bytes(next_hop_encrypted_routing_information),
357 HeaderIntegrityMac::from_bytes(next_hop_integrity_mac),
358 );
359
360 ParsedRawRoutingInformation {
361 version: Version::from_bytes([version_ref[0], version_ref[1], version_ref[2]]),
362 data: ParsedRawRoutingInformationData::ForwardHop {
363 next_hop_address: NodeAddressBytes::from_bytes(next_hop_address),
364 delay: Delay::from_bytes(delay_bytes),
365 new_routing_information: Box::new(next_hop_encapsulated_routing_info),
366 },
367 }
368 }
369
370 fn parse_as_final_hop(self) -> ParsedRawRoutingInformation {
372 let mut i = 1;
373
374 let version_ref = &self.value[i..i + VERSION_LENGTH];
375 i += VERSION_LENGTH;
376
377 let mut destination_bytes: [u8; DESTINATION_ADDRESS_LENGTH] = Default::default();
378 destination_bytes.copy_from_slice(&self.value[i..i + DESTINATION_ADDRESS_LENGTH]);
379 i += DESTINATION_ADDRESS_LENGTH;
380 let destination = DestinationAddressBytes::from_bytes(destination_bytes);
381
382 let mut identifier: [u8; IDENTIFIER_LENGTH] = Default::default();
383 identifier.copy_from_slice(&self.value[i..i + IDENTIFIER_LENGTH]);
384
385 ParsedRawRoutingInformation {
386 version: Version::from_bytes([version_ref[0], version_ref[1], version_ref[2]]),
387 data: ParsedRawRoutingInformationData::FinalHop {
388 destination,
389 identifier,
390 },
391 }
392 }
393}
394
395type TruncatedRoutingInformation = [u8; TRUNCATED_ROUTING_INFO_SIZE];
397
398#[cfg(test)]
399mod preparing_header_layer {
400 use super::*;
401 use crate::constants::HeaderIntegrityHmacAlgorithm;
402 use crate::test_utils::fixtures::expanded_shared_secret_fixture;
403 use crate::{
404 constants::HEADER_INTEGRITY_MAC_SIZE,
405 test_utils::fixtures::{encapsulated_routing_information_fixture, node_address_fixture},
406 };
407
408 #[test]
409 fn it_returns_encrypted_truncated_address_and_flag_concatenated_with_inner_layer_and_mac_on_it()
410 {
411 let node_address = node_address_fixture();
412 let delay = Delay::new_from_nanos(10);
413 let previous_node_routing_keys = expanded_shared_secret_fixture();
414 let inner_layer_routing = encapsulated_routing_information_fixture();
415
416 let version = Version::default();
417 let concatenated_materials: Vec<u8> = [
419 vec![FORWARD_HOP],
420 version.to_bytes().to_vec(),
421 node_address.to_bytes().to_vec(),
422 delay.to_bytes().to_vec(),
423 inner_layer_routing.integrity_mac.as_bytes().to_vec(),
424 inner_layer_routing
425 .enc_routing_information
426 .value
427 .to_vec()
428 .iter()
429 .cloned()
430 .take(TRUNCATED_ROUTING_INFO_SIZE)
431 .collect(),
432 ]
433 .concat();
434
435 let pseudorandom_bytes = crypto::generate_pseudorandom_bytes(
436 previous_node_routing_keys.stream_cipher_key(),
437 &STREAM_CIPHER_INIT_VECTOR,
438 STREAM_CIPHER_OUTPUT_LENGTH,
439 );
440
441 let expected_encrypted_routing_info_vec = utils::bytes::xor(
442 &concatenated_materials,
443 &pseudorandom_bytes[..ENCRYPTED_ROUTING_INFO_SIZE],
444 );
445
446 let expected_routing_mac = crypto::compute_keyed_hmac::<HeaderIntegrityHmacAlgorithm>(
447 previous_node_routing_keys.header_integrity_hmac_key(),
448 &expected_encrypted_routing_info_vec,
449 );
450 let mut expected_routing_mac = expected_routing_mac.into_bytes().to_vec();
451 expected_routing_mac.truncate(HEADER_INTEGRITY_MAC_SIZE);
452
453 let next_layer_routing =
454 RoutingInformation::new(node_address, delay, inner_layer_routing, Version::default())
455 .encrypt(previous_node_routing_keys.stream_cipher_key())
456 .encapsulate_with_mac(previous_node_routing_keys.header_integrity_hmac_key());
457
458 assert_eq!(
459 expected_encrypted_routing_info_vec,
460 next_layer_routing.enc_routing_information.value.to_vec()
461 );
462 assert_eq!(
463 expected_routing_mac,
464 next_layer_routing.integrity_mac.as_bytes().to_vec()
465 );
466 }
467}
468
469#[cfg(test)]
470mod encrypting_routing_information {
471 use super::*;
472 use crate::{
473 crypto::STREAM_CIPHER_KEY_SIZE,
474 test_utils::fixtures::{header_integrity_mac_fixture, node_address_fixture},
475 };
476
477 #[test]
478 fn it_is_possible_to_decrypt_it_to_recover_original_data() {
479 let key = [2u8; STREAM_CIPHER_KEY_SIZE];
480 let flag = FORWARD_HOP;
481 let address = node_address_fixture();
482 let delay = Delay::new_from_nanos(15);
483 let mac = header_integrity_mac_fixture();
484 let next_routing = [8u8; TRUNCATED_ROUTING_INFO_SIZE];
485
486 let version = Version::default();
487 let encryption_data = [
488 vec![flag],
489 version.to_bytes().to_vec(),
490 address.to_bytes().to_vec(),
491 delay.to_bytes().to_vec(),
492 mac.as_bytes().to_vec(),
493 next_routing.to_vec(),
494 ]
495 .concat();
496
497 let routing_information = RoutingInformation {
498 flag: FORWARD_HOP,
499 version,
500 node_address: address,
501 delay,
502 header_integrity_mac: mac,
503 next_routing_information: next_routing,
504 };
505
506 let encrypted_data = routing_information.encrypt(&key);
507 let decryption_key_source = crypto::generate_pseudorandom_bytes(
508 &key,
509 &STREAM_CIPHER_INIT_VECTOR,
510 STREAM_CIPHER_OUTPUT_LENGTH,
511 );
512 let decryption_key = &decryption_key_source[..ENCRYPTED_ROUTING_INFO_SIZE];
513 let decrypted_data = utils::bytes::xor(&encrypted_data.value, decryption_key);
514 assert_eq!(encryption_data, decrypted_data);
515 }
516}
517
518#[cfg(test)]
519mod truncating_routing_information {
520 use crate::test_utils::fixtures::encrypted_routing_information_fixture;
521
522 #[test]
523 fn it_does_not_change_prefixed_data() {
524 let encrypted_routing_info = encrypted_routing_information_fixture();
525 let routing_info_data_copy = encrypted_routing_info.value;
526
527 let truncated_routing_info = encrypted_routing_info.truncate();
528 for i in 0..truncated_routing_info.len() {
529 assert_eq!(truncated_routing_info[i], routing_info_data_copy[i]);
530 }
531 }
532}
533
534#[cfg(test)]
535mod parse_decrypted_routing_information {
536 use super::*;
537 use crate::{
538 header::routing::ENCRYPTED_ROUTING_INFO_SIZE,
539 test_utils::fixtures::{header_integrity_mac_fixture, node_address_fixture},
540 };
541
542 #[test]
543 fn it_returns_next_hop_address_integrity_mac_enc_routing_info() {
544 let flag = FORWARD_HOP;
545 let address_fixture = node_address_fixture();
546 let delay = Delay::new_from_nanos(10);
547 let integrity_mac = header_integrity_mac_fixture();
548 let next_routing_information = [1u8; ENCRYPTED_ROUTING_INFO_SIZE];
549 let version = Version::default();
550
551 let data = [
552 vec![flag],
553 version.to_bytes().to_vec(),
554 address_fixture.to_bytes().to_vec(),
555 delay.to_bytes().to_vec(),
556 integrity_mac.as_bytes().to_vec(),
557 next_routing_information.to_vec(),
558 ]
559 .concat();
560
561 let raw_routing_info = RawRoutingInformation { value: data };
562
563 let parsed = raw_routing_info.parse().unwrap();
564 match parsed.data {
565 ParsedRawRoutingInformationData::ForwardHop {
566 next_hop_address,
567 delay: _,
568 new_routing_information,
569 } => {
570 assert_eq!(address_fixture, next_hop_address);
571 assert_eq!(
572 integrity_mac.as_bytes().to_vec(),
573 new_routing_information.integrity_mac.as_bytes().to_vec()
574 );
575 assert_eq!(
576 next_routing_information.to_vec(),
577 new_routing_information
578 .enc_routing_information
579 .as_ref()
580 .to_vec()
581 );
582 }
583 ParsedRawRoutingInformationData::FinalHop { .. } => panic!(),
584 }
585 }
586}