1#[cfg(feature = "bench")]
34pub(crate) mod bench_utils;
35#[cfg(feature = "counter-galois-onion")]
36pub(crate) mod cgo;
37pub(crate) mod tor1;
38
39use crate::{Error, Result};
40use derive_deftly::Deftly;
41use tor_cell::{
42    chancell::{BoxedCellBody, ChanCmd},
43    relaycell::msg::SendmeTag,
44};
45use tor_memquota::derive_deftly_template_HasMemoryCost;
46
47use super::binding::CircuitBinding;
48
49#[cfg_attr(feature = "bench", visibility::make(pub))]
51#[derive(Clone, derive_more::From, derive_more::Into)]
52pub(crate) struct RelayCellBody(BoxedCellBody);
53
54impl AsRef<[u8]> for RelayCellBody {
55    fn as_ref(&self) -> &[u8] {
56        &self.0[..]
57    }
58}
59impl AsMut<[u8]> for RelayCellBody {
60    fn as_mut(&mut self) -> &mut [u8] {
61        &mut self.0[..]
62    }
63}
64
65#[cfg_attr(feature = "bench", visibility::make(pub))]
68pub(crate) trait CryptInit: Sized {
69    fn seed_len() -> usize;
71    fn initialize(seed: &[u8]) -> Result<Self>;
73    fn construct<K: super::handshake::KeyGenerator>(keygen: K) -> Result<Self> {
75        let seed = keygen.expand(Self::seed_len())?;
76        Self::initialize(&seed[..])
77    }
78}
79
80#[cfg_attr(feature = "bench", visibility::make(pub))]
85pub(crate) trait ClientLayer<F, B>
86where
87    F: OutboundClientLayer,
88    B: InboundClientLayer,
89{
90    fn split_client_layer(self) -> (F, B, CircuitBinding);
93}
94
95#[allow(dead_code)] #[cfg_attr(feature = "bench", visibility::make(pub))]
100pub(crate) trait RelayLayer<F, B>
101where
102    F: OutboundRelayLayer,
103    B: InboundRelayLayer,
104{
105    fn split_relay_layer(self) -> (F, B, CircuitBinding);
108}
109
110#[allow(dead_code)] #[cfg_attr(feature = "bench", visibility::make(pub))]
113pub(crate) trait InboundRelayLayer {
114    fn originate(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag;
119    fn encrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody);
121}
122
123#[allow(dead_code)]
125#[cfg_attr(feature = "bench", visibility::make(pub))]
126pub(crate) trait OutboundRelayLayer {
127    fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
131}
132
133#[cfg_attr(feature = "bench", visibility::make(pub))]
136pub(crate) trait OutboundClientLayer {
137    fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag;
142    fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody);
144}
145
146#[cfg_attr(feature = "bench", visibility::make(pub))]
149pub(crate) trait InboundClientLayer {
150    fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
154}
155
156#[derive(Copy, Clone, Eq, PartialEq, Debug, Deftly, Ord, PartialOrd)]
160#[derive_deftly(HasMemoryCost)]
161pub struct HopNum(u8);
162
163impl HopNum {
164    pub fn display(&self) -> HopNumDisplay {
172        HopNumDisplay(*self)
173    }
174
175    pub(crate) fn is_first_hop(&self) -> bool {
177        self.0 == 0
178    }
179}
180
181#[derive(Copy, Clone, Eq, PartialEq, Debug)]
187pub struct HopNumDisplay(HopNum);
188
189impl std::fmt::Display for HopNumDisplay {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
191        let hop_num: u8 = self.0.into();
192
193        write!(f, "#{}", hop_num + 1)
194    }
195}
196
197impl From<HopNum> for u8 {
198    fn from(hop: HopNum) -> u8 {
199        hop.0
200    }
201}
202
203impl From<u8> for HopNum {
204    fn from(v: u8) -> HopNum {
205        HopNum(v)
206    }
207}
208
209impl From<HopNum> for usize {
210    fn from(hop: HopNum) -> usize {
211        hop.0 as usize
212    }
213}
214
215#[cfg_attr(feature = "bench", visibility::make(pub), derive(Default))]
218pub(crate) struct OutboundClientCrypt {
219    layers: Vec<Box<dyn OutboundClientLayer + Send>>,
222}
223
224#[cfg_attr(feature = "bench", visibility::make(pub), derive(Default))]
227pub(crate) struct InboundClientCrypt {
228    layers: Vec<Box<dyn InboundClientLayer + Send>>,
231}
232
233impl OutboundClientCrypt {
234    #[cfg_attr(feature = "bench", visibility::make(pub))]
236    pub(crate) fn new() -> Self {
237        OutboundClientCrypt { layers: Vec::new() }
238    }
239    #[cfg_attr(feature = "bench", visibility::make(pub))]
247    pub(crate) fn encrypt(
248        &mut self,
249        cmd: ChanCmd,
250        cell: &mut RelayCellBody,
251        hop: HopNum,
252    ) -> Result<SendmeTag> {
253        let hop: usize = hop.into();
254        if hop >= self.layers.len() {
255            return Err(Error::NoSuchHop);
256        }
257
258        let mut layers = self.layers.iter_mut().take(hop + 1).rev();
259        let first_layer = layers.next().ok_or(Error::NoSuchHop)?;
260        let tag = first_layer.originate_for(cmd, cell);
261        for layer in layers {
262            layer.encrypt_outbound(cmd, cell);
263        }
264        Ok(tag)
265    }
266
267    pub(crate) fn add_layer(&mut self, layer: Box<dyn OutboundClientLayer + Send>) {
269        assert!(self.layers.len() < u8::MAX as usize);
270        self.layers.push(layer);
271    }
272
273    pub(crate) fn n_layers(&self) -> usize {
275        self.layers.len()
276    }
277}
278
279impl InboundClientCrypt {
280    #[cfg_attr(feature = "bench", visibility::make(pub))]
282    pub(crate) fn new() -> Self {
283        InboundClientCrypt { layers: Vec::new() }
284    }
285    #[cfg_attr(feature = "bench", visibility::make(pub))]
290    pub(crate) fn decrypt(
291        &mut self,
292        cmd: ChanCmd,
293        cell: &mut RelayCellBody,
294    ) -> Result<(HopNum, SendmeTag)> {
295        for (hopnum, layer) in self.layers.iter_mut().enumerate() {
296            if let Some(tag) = layer.decrypt_inbound(cmd, cell) {
297                let hopnum = HopNum(u8::try_from(hopnum).expect("Somehow > 255 hops"));
298                return Ok((hopnum, tag));
299            }
300        }
301        Err(Error::BadCellAuth)
302    }
303    pub(crate) fn add_layer(&mut self, layer: Box<dyn InboundClientLayer + Send>) {
305        assert!(self.layers.len() < u8::MAX as usize);
306        self.layers.push(layer);
307    }
308
309    #[allow(dead_code)]
313    pub(crate) fn n_layers(&self) -> usize {
314        self.layers.len()
315    }
316}
317
318pub(crate) type Tor1RelayCrypto =
320    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes128Ctr, tor_llcrypto::d::Sha1>;
321
322#[cfg(feature = "hs-common")]
326pub(crate) type Tor1Hsv3RelayCrypto =
327    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes256Ctr, tor_llcrypto::d::Sha3_256>;
328
329#[cfg(feature = "counter-galois-onion")]
335pub(crate) type CgoRelayCrypto = cgo::CryptStatePair<aes::Aes128, aes::Aes128Enc>;
336
337#[cfg(test)]
338mod test {
339    #![allow(clippy::bool_assert_comparison)]
341    #![allow(clippy::clone_on_copy)]
342    #![allow(clippy::dbg_macro)]
343    #![allow(clippy::mixed_attributes_style)]
344    #![allow(clippy::print_stderr)]
345    #![allow(clippy::print_stdout)]
346    #![allow(clippy::single_char_pattern)]
347    #![allow(clippy::unwrap_used)]
348    #![allow(clippy::unchecked_duration_subtraction)]
349    #![allow(clippy::useless_vec)]
350    #![allow(clippy::needless_pass_by_value)]
351    use super::*;
354    use rand::{RngCore, seq::IndexedRandom as _};
355    use tor_basic_utils::{RngExt as _, test_rng::testing_rng};
356    use tor_bytes::SecretBuf;
357    use tor_cell::relaycell::RelayCellFormat;
358
359    pub(crate) fn add_layers(
360        cc_out: &mut OutboundClientCrypt,
361        cc_in: &mut InboundClientCrypt,
362        pair: Tor1RelayCrypto,
363    ) {
364        let (outbound, inbound, _) = pair.split_client_layer();
365        cc_out.add_layer(Box::new(outbound));
366        cc_in.add_layer(Box::new(inbound));
367    }
368
369    #[test]
370    fn roundtrip() {
371        use crate::crypto::handshake::ShakeKeyGenerator as KGen;
373        fn s(seed: &[u8]) -> SecretBuf {
374            seed.to_vec().into()
375        }
376
377        let seed1 = s(b"hidden we are free");
378        let seed2 = s(b"free to speak, to free ourselves");
379        let seed3 = s(b"free to hide no more");
380
381        let mut cc_out = OutboundClientCrypt::new();
382        let mut cc_in = InboundClientCrypt::new();
383        let pair = Tor1RelayCrypto::construct(KGen::new(seed1.clone())).unwrap();
384        add_layers(&mut cc_out, &mut cc_in, pair);
385        let pair = Tor1RelayCrypto::construct(KGen::new(seed2.clone())).unwrap();
386        add_layers(&mut cc_out, &mut cc_in, pair);
387        let pair = Tor1RelayCrypto::construct(KGen::new(seed3.clone())).unwrap();
388        add_layers(&mut cc_out, &mut cc_in, pair);
389
390        assert_eq!(cc_in.n_layers(), 3);
391        assert_eq!(cc_out.n_layers(), 3);
392
393        let (mut r1f, mut r1b, _) = Tor1RelayCrypto::construct(KGen::new(seed1))
394            .unwrap()
395            .split_relay_layer();
396        let (mut r2f, mut r2b, _) = Tor1RelayCrypto::construct(KGen::new(seed2))
397            .unwrap()
398            .split_relay_layer();
399        let (mut r3f, mut r3b, _) = Tor1RelayCrypto::construct(KGen::new(seed3))
400            .unwrap()
401            .split_relay_layer();
402        let cmd = ChanCmd::RELAY;
403
404        let mut rng = testing_rng();
405        for _ in 1..300 {
406            let mut cell = Box::new([0_u8; 509]);
408            let mut cell_orig = [0_u8; 509];
409            rng.fill_bytes(&mut cell_orig);
410            cell.copy_from_slice(&cell_orig);
411            let mut cell = cell.into();
412            let _tag = cc_out.encrypt(cmd, &mut cell, 2.into()).unwrap();
413            assert_ne!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
414            assert!(r1f.decrypt_outbound(cmd, &mut cell).is_none());
415            assert!(r2f.decrypt_outbound(cmd, &mut cell).is_none());
416            assert!(r3f.decrypt_outbound(cmd, &mut cell).is_some());
417
418            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
419
420            let mut cell = Box::new([0_u8; 509]);
422            let mut cell_orig = [0_u8; 509];
423            rng.fill_bytes(&mut cell_orig);
424            cell.copy_from_slice(&cell_orig);
425            let mut cell = cell.into();
426
427            r3b.originate(cmd, &mut cell);
428            r2b.encrypt_inbound(cmd, &mut cell);
429            r1b.encrypt_inbound(cmd, &mut cell);
430            let (layer, _tag) = cc_in.decrypt(cmd, &mut cell).unwrap();
431            assert_eq!(layer, 2.into());
432            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
433
434            }
436
437        {
439            let mut cell = Box::new([0_u8; 509]).into();
440            let err = cc_out.encrypt(cmd, &mut cell, 10.into());
441            assert!(matches!(err, Err(Error::NoSuchHop)));
442        }
443
444        {
446            let mut cell = Box::new([0_u8; 509]).into();
447            let err = cc_in.decrypt(cmd, &mut cell);
448            assert!(matches!(err, Err(Error::BadCellAuth)));
449        }
450    }
451
452    #[test]
453    fn hop_num_display() {
454        for i in 0..10 {
455            let hop_num = HopNum::from(i);
456            let expect = format!("#{}", i + 1);
457
458            assert_eq!(expect, hop_num.display().to_string());
459        }
460    }
461
462    fn clean_cell_fields(cell: &mut RelayCellBody, format: RelayCellFormat) {
467        use super::tor1;
468        match format {
469            RelayCellFormat::V0 => {
470                cell.0[tor1::RECOGNIZED_RANGE].fill(0);
471                cell.0[tor1::DIGEST_RANGE].fill(0);
472            }
473            RelayCellFormat::V1 => {
474                cell.0[0..16].fill(0);
475            }
476            _ => {
477                panic!("Unrecognized format!");
478            }
479        }
480    }
481
482    fn test_fwd_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
484    where
485        CS: CryptInit + ClientLayer<CF, CB>,
486        RS: CryptInit + RelayLayer<RF, RB>,
487        CF: OutboundClientLayer,
488        CB: InboundClientLayer,
489        RF: OutboundRelayLayer,
490        RB: InboundRelayLayer,
491    {
492        let mut rng = testing_rng();
493        assert_eq!(CS::seed_len(), RS::seed_len());
494        let mut seed = vec![0; CS::seed_len()];
495        rng.fill_bytes(&mut seed[..]);
496        let (mut client, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
497        let (mut relay, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
498
499        for _ in 0..5 {
500            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
501            rng.fill_bytes(&mut cell.0[..]);
502            clean_cell_fields(&mut cell, format);
503            let msg_orig = cell.clone();
504
505            let ctag = client.originate_for(ChanCmd::RELAY, &mut cell);
506            assert_ne!(cell.0[16..], msg_orig.0[16..]);
507            let rtag = relay.decrypt_outbound(ChanCmd::RELAY, &mut cell);
508            clean_cell_fields(&mut cell, format);
509            assert_eq!(cell.0[..], msg_orig.0[..]);
510            assert_eq!(rtag, Some(ctag));
511        }
512    }
513
514    fn test_rev_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
516    where
517        CS: CryptInit + ClientLayer<CF, CB>,
518        RS: CryptInit + RelayLayer<RF, RB>,
519        CF: OutboundClientLayer,
520        CB: InboundClientLayer,
521        RF: OutboundRelayLayer,
522        RB: InboundRelayLayer,
523    {
524        let mut rng = testing_rng();
525        assert_eq!(CS::seed_len(), RS::seed_len());
526        let mut seed = vec![0; CS::seed_len()];
527        rng.fill_bytes(&mut seed[..]);
528        let (_, mut client, _) = CS::initialize(&seed).unwrap().split_client_layer();
529        let (_, mut relay, _) = RS::initialize(&seed).unwrap().split_relay_layer();
530
531        for _ in 0..5 {
532            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
533            rng.fill_bytes(&mut cell.0[..]);
534            clean_cell_fields(&mut cell, format);
535            let msg_orig = cell.clone();
536
537            let rtag = relay.originate(ChanCmd::RELAY, &mut cell);
538            assert_ne!(cell.0[16..], msg_orig.0[16..]);
539            let ctag = client.decrypt_inbound(ChanCmd::RELAY, &mut cell);
540            clean_cell_fields(&mut cell, format);
541            assert_eq!(cell.0[..], msg_orig.0[..]);
542            assert_eq!(ctag, Some(rtag));
543        }
544    }
545
546    fn test_fwd_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
547    where
548        CS: CryptInit + ClientLayer<CF, CB>,
549        RS: CryptInit + RelayLayer<RF, RB>,
550        CF: OutboundClientLayer + Send + 'static,
551        CB: InboundClientLayer,
552        RF: OutboundRelayLayer,
553        RB: InboundRelayLayer,
554    {
555        let mut rng = testing_rng();
556        assert_eq!(CS::seed_len(), RS::seed_len());
557        let mut client = OutboundClientCrypt::new();
558        let mut relays = Vec::new();
559        for _ in 0..3 {
560            let mut seed = vec![0; CS::seed_len()];
561            rng.fill_bytes(&mut seed[..]);
562            let (client_layer, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
563            let (relay_layer, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
564            client.add_layer(Box::new(client_layer));
565            relays.push(relay_layer);
566        }
567
568        'cell_loop: for _ in 0..32 {
569            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
570            rng.fill_bytes(&mut cell.0[..]);
571            clean_cell_fields(&mut cell, format);
572            let msg_orig = cell.clone();
573            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
574                .choose(&mut rng)
575                .unwrap();
576            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
577
578            let ctag = client.encrypt(cmd, &mut cell, hop.into()).unwrap();
579
580            for r_idx in 0..=hop {
581                let rtag = relays[r_idx as usize].decrypt_outbound(cmd, &mut cell);
582                if let Some(rtag) = rtag {
583                    clean_cell_fields(&mut cell, format);
584                    assert_eq!(cell.0[..], msg_orig.0[..]);
585                    assert_eq!(rtag, ctag);
586                    continue 'cell_loop;
587                }
588            }
589            panic!("None of the relays thought that this cell was recognized!");
590        }
591    }
592
593    fn test_rev_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
594    where
595        CS: CryptInit + ClientLayer<CF, CB>,
596        RS: CryptInit + RelayLayer<RF, RB>,
597        CF: OutboundClientLayer,
598        CB: InboundClientLayer + Send + 'static,
599        RF: OutboundRelayLayer,
600        RB: InboundRelayLayer,
601    {
602        let mut rng = testing_rng();
603        assert_eq!(CS::seed_len(), RS::seed_len());
604        let mut client = InboundClientCrypt::new();
605        let mut relays = Vec::new();
606        for _ in 0..3 {
607            let mut seed = vec![0; CS::seed_len()];
608            rng.fill_bytes(&mut seed[..]);
609            let (_, client_layer, _) = CS::initialize(&seed).unwrap().split_client_layer();
610            let (_, relay_layer, _) = RS::initialize(&seed).unwrap().split_relay_layer();
611            client.add_layer(Box::new(client_layer));
612            relays.push(relay_layer);
613        }
614
615        for _ in 0..32 {
616            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
617            rng.fill_bytes(&mut cell.0[..]);
618            clean_cell_fields(&mut cell, format);
619            let msg_orig = cell.clone();
620            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
621                .choose(&mut rng)
622                .unwrap();
623            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
624
625            let rtag = relays[hop as usize].originate(cmd, &mut cell);
626            for r_idx in (0..hop.into()).rev() {
627                relays[r_idx as usize].encrypt_inbound(cmd, &mut cell);
628            }
629
630            let (observed_hop, ctag) = client.decrypt(cmd, &mut cell).unwrap();
631            assert_eq!(observed_hop, hop.into());
632            clean_cell_fields(&mut cell, format);
633            assert_eq!(cell.0[..], msg_orig.0[..]);
634            assert_eq!(ctag, rtag);
635        }
636    }
637
638    macro_rules! integration_tests { { $modname:ident($fmt:expr, $ctype:ty, $rtype:ty) } => {
639        mod $modname {
640            use super::*;
641            #[test]
642            fn test_fwd_one_hop() {
643                super::test_fwd_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
644            }
645            #[test]
646            fn test_rev_one_hop() {
647                super::test_rev_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
648            }
649            #[test]
650            fn test_fwd_three_hops_leaky() {
651                super::test_fwd_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
652            }
653            #[test]
654            fn test_rev_three_hops_leaky() {
655                super::test_rev_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
656            }
657        }
658    }}
659
660    integration_tests! { tor1(RelayCellFormat::V0, Tor1RelayCrypto, Tor1RelayCrypto) }
661    #[cfg(feature = "hs-common")]
662    integration_tests! { tor1_hs(RelayCellFormat::V0, Tor1Hsv3RelayCrypto, Tor1Hsv3RelayCrypto) }
663
664    #[cfg(feature = "counter-galois-onion")]
665    integration_tests! {
666        cgo_aes128(RelayCellFormat::V1,
667            cgo::CryptStatePair<aes::Aes128Dec, aes::Aes128Enc>,cgo::CryptStatePair<aes::Aes128Enc, aes::Aes128Enc> )
670    }
671    #[cfg(feature = "counter-galois-onion")]
672    integration_tests! {
673        cgo_aes256(RelayCellFormat::V1,
674            cgo::CryptStatePair<aes::Aes256Dec, aes::Aes256Enc>,cgo::CryptStatePair<aes::Aes256Enc, aes::Aes256Enc> )
677    }
678}