1#![allow(dead_code)] use aes::{Aes128, Aes128Dec, Aes128Enc, Aes256, Aes256Dec, Aes256Enc};
22use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, BlockSizeUser, StreamCipher as _};
23use digest::KeyInit;
24use polyval::{Polyval, universal_hash::UniversalHash};
25use tor_cell::{
26 chancell::{CELL_DATA_LEN, ChanCmd},
27 relaycell::msg::SendmeTag,
28};
29use tor_error::internal;
30use zeroize::Zeroizing;
31
32use super::{CryptInit, RelayCellBody};
33use crate::{client::circuit::CircuitBinding, util::ct};
34
35const CGO_TAG_LEN: usize = 16;
37const CGO_PAYLOAD_LEN: usize = CELL_DATA_LEN - CGO_TAG_LEN;
39
40const CGO_AD_LEN: usize = 16;
44
45const HLEN_UIV: usize = CGO_TAG_LEN + CGO_AD_LEN;
47
48const BLK_LEN: usize = 16;
51type BlockLen = typenum::U16;
54type Block = [u8; BLK_LEN];
56
57#[cfg_attr(feature = "bench", visibility::make(pub))]
62pub(crate) trait BlkCipher:
63 BlockCipher + KeyInit + BlockSizeUser<BlockSize = BlockLen> + Clone
64{
65 const KEY_LEN: usize;
67}
68
69#[cfg_attr(feature = "bench", visibility::make(pub))]
74pub(crate) trait BlkCipherEnc: BlkCipher + BlockEncrypt {}
75
76#[cfg_attr(feature = "bench", visibility::make(pub))]
81pub(crate) trait BlkCipherDec: BlkCipher + BlockDecrypt {}
82
83impl BlkCipher for Aes128 {
84 const KEY_LEN: usize = 16;
85}
86impl BlkCipherEnc for Aes128 {}
87impl BlkCipherDec for Aes128 {}
88impl BlkCipher for Aes128Enc {
89 const KEY_LEN: usize = 16;
90}
91impl BlkCipherEnc for Aes128Enc {}
92impl BlkCipher for Aes128Dec {
93 const KEY_LEN: usize = 16;
94}
95impl BlkCipherDec for Aes128Dec {}
96
97impl BlkCipher for Aes256 {
98 const KEY_LEN: usize = 32;
99}
100impl BlkCipherEnc for Aes256 {}
101impl BlkCipherDec for Aes256 {}
102impl BlkCipher for Aes256Enc {
103 const KEY_LEN: usize = 32;
104}
105impl BlkCipherEnc for Aes256Enc {}
106impl BlkCipher for Aes256Dec {
107 const KEY_LEN: usize = 32;
108}
109impl BlkCipherDec for Aes256Dec {}
110
111mod et {
113 use super::*;
114
115 pub(super) type EtTweak<'a> = (&'a [u8; CGO_TAG_LEN], u8, &'a [u8; CGO_PAYLOAD_LEN]);
120 pub(super) const TLEN_ET: usize = CGO_TAG_LEN + 1 + CGO_PAYLOAD_LEN;
122
123 #[derive(Clone)]
129 pub(super) struct EtCipher<BC: BlkCipher> {
130 kb: BC,
132 ku: Polyval,
134 }
135 impl<BC: BlkCipher> EtCipher<BC> {
136 fn compute_tweak_hash(&self, tweak: EtTweak<'_>) -> Zeroizing<Block> {
139 let mut ku = self.ku.clone();
142
143 let mut block1 = Zeroizing::new([0_u8; 16]);
144 block1[0] = tweak.1;
145 block1[1..16].copy_from_slice(&tweak.2[0..15]);
146 ku.update(&[(*tweak.0).into(), (*block1).into()]);
147 ku.update_padded(&tweak.2[15..]);
148 Zeroizing::new(ku.finalize().into())
149 }
150 }
151 impl<BC: BlkCipherEnc> EtCipher<BC> {
152 pub(super) fn encrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
154 let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
156 xor_into(block, &tag);
157 self.kb.encrypt_block(block.into());
158 xor_into(block, &tag);
159 }
160 }
161 impl<BC: BlkCipherDec> EtCipher<BC> {
162 pub(super) fn decrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
164 let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
166 xor_into(block, &tag);
167 self.kb.decrypt_block(block.into());
168 xor_into(block, &tag);
169 }
170 }
171 impl<BC: BlkCipher> CryptInit for EtCipher<BC> {
172 fn seed_len() -> usize {
173 BC::key_size() + polyval::KEY_SIZE
174 }
175 fn initialize(seed: &[u8]) -> crate::Result<Self> {
176 if seed.len() != Self::seed_len() {
179 return Err(internal!("Invalid seed length").into());
180 }
181 let (kb, ku) = seed.split_at(BC::key_size());
182 Ok(Self {
183 kb: BC::new(kb.into()),
184 ku: Polyval::new(ku.into()),
185 })
186 }
187 }
188}
189
190mod prf {
192 use tor_error::internal;
193
194 use super::*;
195
196 type PrfTweak = [u8; 16];
198 const PRF_N0_LEN: usize = CGO_PAYLOAD_LEN;
200 const PRF_N1_OFFSET: usize = 31 * 16;
202 const _: () = assert!(PRF_N1_OFFSET >= PRF_N0_LEN);
203
204 #[derive(Clone)]
209 pub(super) struct Prf<BC: BlkCipherEnc> {
210 k: BC,
212 b: Polyval,
214 }
215 impl<BC: BlkCipherEnc> Prf<BC> {
216 fn cipher(&self, tweak: &PrfTweak, t: bool) -> ctr::Ctr128BE<BC> {
219 use {
220 cipher::{InnerIvInit as _, StreamCipherSeek as _},
221 ctr::CtrCore,
222 };
223 let mut b = self.b.clone(); b.update(&[(*tweak).into()]);
225 let mut iv = b.finalize();
226 *iv.last_mut().expect("no last element?") &= 0xC0; let mut cipher: ctr::Ctr128BE<BC> = cipher::StreamCipherCoreWrapper::from_core(
228 CtrCore::inner_iv_init(self.k.clone(), &iv),
229 );
230 if t {
231 debug_assert_eq!(cipher.current_pos::<u32>(), 0_u32);
232 cipher.seek(PRF_N1_OFFSET);
233 }
234
235 cipher
236 }
237
238 pub(super) fn xor_n0_stream(&self, tweak: &PrfTweak, out: &mut [u8; PRF_N0_LEN]) {
241 let mut stream = self.cipher(tweak, false);
242 stream.apply_keystream(out);
243 }
244
245 pub(super) fn get_n1_stream(&self, tweak: &PrfTweak, n: usize) -> Zeroizing<Vec<u8>> {
248 let mut output = Zeroizing::new(vec![0_u8; n]);
249 self.cipher(tweak, true).apply_keystream(output.as_mut());
250 output
251 }
252 }
253
254 impl<BC: BlkCipherEnc> CryptInit for Prf<BC> {
255 fn seed_len() -> usize {
256 BC::key_size() + polyval::KEY_SIZE
257 }
258 fn initialize(seed: &[u8]) -> crate::Result<Self> {
259 if seed.len() != Self::seed_len() {
260 return Err(internal!("Invalid seed length").into());
261 }
262 let (k, b) = seed.split_at(BC::key_size());
263 Ok(Self {
264 k: BC::new(k.into()),
265 b: Polyval::new(b.into()),
266 })
267 }
268 }
269}
270
271mod uiv {
275 use super::*;
276
277 pub(super) type UivTweak<'a> = (&'a [u8; BLK_LEN], u8);
279
280 #[derive(Clone)]
282 pub(super) struct Uiv<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
283 j: et::EtCipher<EtBC>,
285 s: prf::Prf<PrfBC>,
287
288 #[cfg(test)]
293 pub(super) keys: Zeroizing<Vec<u8>>,
294 }
295
296 fn split(
299 cell_body: &mut [u8; CELL_DATA_LEN],
300 ) -> (&mut [u8; CGO_TAG_LEN], &mut [u8; CGO_PAYLOAD_LEN]) {
301 let (left, right) = cell_body.split_at_mut(CGO_TAG_LEN);
303 (
304 left.try_into().expect("split_at_mut returned wrong size!"),
305 right.try_into().expect("split_at_mut returned wrong size!"),
306 )
307 }
308
309 impl<EtBC: BlkCipherEnc, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
310 pub(super) fn encrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
314 let (left, right) = split(cell_body);
319 self.j.encrypt((tweak.0, tweak.1, right), left);
320 self.s.xor_n0_stream(left, right);
321 }
322 }
323 impl<EtBC: BlkCipherDec, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
324 pub(super) fn decrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
328 let (left, right) = split(cell_body);
333 self.s.xor_n0_stream(left, right);
334 self.j.decrypt((tweak.0, tweak.1, right), left);
335 }
336 }
337 impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
338 pub(super) fn update(&mut self, nonce: &mut [u8; BLK_LEN]) {
343 let n_bytes = Self::seed_len() + BLK_LEN;
351 let seed = self.s.get_n1_stream(nonce, n_bytes);
352 #[cfg(test)]
353 {
354 self.keys = Zeroizing::new(seed[..Self::seed_len()].to_vec());
355 }
356 let (j, s, n) = Self::split_seed(&seed);
357 self.j = et::EtCipher::initialize(j).expect("Invalid slice len");
358 self.s = prf::Prf::initialize(s).expect("invalid slice len");
359 nonce[..].copy_from_slice(n);
360 }
361
362 fn split_seed(seed: &[u8]) -> (&[u8], &[u8], &[u8]) {
364 let len_j = et::EtCipher::<EtBC>::seed_len();
365 let len_s = prf::Prf::<PrfBC>::seed_len();
366 (
367 &seed[0..len_j],
368 &seed[len_j..len_j + len_s],
369 &seed[len_j + len_s..],
370 )
371 }
372 }
373
374 impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for Uiv<EtBC, PrfBC> {
375 fn seed_len() -> usize {
376 super::et::EtCipher::<EtBC>::seed_len() + super::prf::Prf::<PrfBC>::seed_len()
377 }
378 fn initialize(seed: &[u8]) -> crate::Result<Self> {
379 if seed.len() != Self::seed_len() {
380 return Err(internal!("Invalid seed length").into());
381 }
382 #[cfg(test)]
383 let keys = Zeroizing::new(seed.to_vec());
384 let (j, s, n) = Self::split_seed(seed);
385 debug_assert!(n.is_empty());
386 Ok(Self {
387 j: et::EtCipher::initialize(j)?,
388 s: prf::Prf::initialize(s)?,
389 #[cfg(test)]
390 keys,
391 })
392 }
393 }
394}
395
396fn xor_into<const N: usize>(output: &mut [u8; N], input: &[u8; N]) {
398 for i in 0..N {
399 output[i] ^= input[i];
400 }
401}
402
403#[inline]
408fn first_block(bytes: &[u8]) -> &[u8; BLK_LEN] {
409 bytes[0..BLK_LEN].try_into().expect("Slice too short!")
410}
411
412#[derive(Clone)]
414struct CryptState<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
415 uiv: uiv::Uiv<EtBC, PrfBC>,
417 nonce: Zeroizing<[u8; BLK_LEN]>,
419 tag: Zeroizing<[u8; BLK_LEN]>,
421}
422
423impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for CryptState<EtBC, PrfBC> {
424 fn seed_len() -> usize {
425 uiv::Uiv::<EtBC, PrfBC>::seed_len() + BLK_LEN
426 }
427 fn initialize(seed: &[u8]) -> crate::Result<Self> {
429 if seed.len() != Self::seed_len() {
430 return Err(internal!("Invalid seed length").into());
431 }
432 let (j_s, n) = seed.split_at(uiv::Uiv::<EtBC, PrfBC>::seed_len());
433 Ok(Self {
434 uiv: uiv::Uiv::initialize(j_s)?,
435 nonce: Zeroizing::new(n.try_into().expect("invalid splice length")),
436 tag: Zeroizing::new([0; BLK_LEN]),
437 })
438 }
439}
440
441#[cfg_attr(feature = "bench", visibility::make(pub))]
443#[derive(Clone, derive_more::From)]
444pub(crate) struct ClientOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
445where
446 EtBC: BlkCipherDec,
447 PrfBC: BlkCipherEnc;
448impl<EtBC, PrfBC> super::OutboundClientLayer for ClientOutbound<EtBC, PrfBC>
449where
450 EtBC: BlkCipherDec,
451 PrfBC: BlkCipherEnc,
452{
453 fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
454 cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
455 self.encrypt_outbound(cmd, cell);
456 self.0.uiv.update(&mut self.0.nonce);
457 SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Block length not a valid sendme tag.")
458 }
459 fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
460 let t_new: [u8; BLK_LEN] = *first_block(&*cell.0);
462
463 self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
466 *self.0.tag = t_new;
467 }
468}
469
470#[cfg_attr(feature = "bench", visibility::make(pub))]
472#[derive(Clone, derive_more::From)]
473pub(crate) struct ClientInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
474where
475 EtBC: BlkCipherDec,
476 PrfBC: BlkCipherEnc;
477impl<EtBC, PrfBC> super::InboundClientLayer for ClientInbound<EtBC, PrfBC>
478where
479 EtBC: BlkCipherDec,
480 PrfBC: BlkCipherEnc,
481{
482 fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
483 let mut t_orig: [u8; BLK_LEN] = *first_block(&*cell.0);
484 self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
489 *self.0.tag = t_orig;
490 if ct::bytes_eq(&cell.0[..CGO_TAG_LEN], &self.0.nonce[..]) {
491 self.0.uiv.update(&mut t_orig);
492 *self.0.nonce = t_orig;
493 Some((*self.0.tag).into())
495 } else {
496 None
497 }
498 }
499}
500
501#[cfg_attr(feature = "bench", visibility::make(pub))]
503#[derive(Clone, derive_more::From)]
504pub(crate) struct RelayOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
505where
506 EtBC: BlkCipherEnc,
507 PrfBC: BlkCipherEnc;
508impl<EtBC, PrfBC> super::OutboundRelayLayer for RelayOutbound<EtBC, PrfBC>
509where
510 EtBC: BlkCipherEnc,
511 PrfBC: BlkCipherEnc,
512{
513 fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
514 let tag = SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Invalid sendme length");
515 self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
518 *self.0.tag = *first_block(&*cell.0);
519 if ct::bytes_eq(self.0.tag.as_ref(), &self.0.nonce[..]) {
520 self.0.uiv.update(&mut self.0.nonce);
521 Some(tag)
522 } else {
523 None
524 }
525 }
526}
527
528#[cfg_attr(feature = "bench", visibility::make(pub))]
530#[derive(Clone, derive_more::From)]
531pub(crate) struct RelayInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
532where
533 EtBC: BlkCipherEnc,
534 PrfBC: BlkCipherEnc;
535impl<EtBC, PrfBC> super::InboundRelayLayer for RelayInbound<EtBC, PrfBC>
536where
537 EtBC: BlkCipherEnc,
538 PrfBC: BlkCipherEnc,
539{
540 fn originate(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
541 cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
542 self.encrypt_inbound(cmd, cell);
543 self.0.nonce.copy_from_slice(&cell.0[0..BLK_LEN]);
544 self.0.uiv.update(&mut self.0.nonce);
545 (*self.0.tag).into()
547 }
548 fn encrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
549 self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
552 *self.0.tag = *first_block(&*cell.0);
553 }
554}
555
556#[cfg_attr(feature = "bench", visibility::make(pub))]
559#[derive(Clone)]
560pub(crate) struct CryptStatePair<EtBC, PrfBC>
561where
562 EtBC: BlkCipher,
563 PrfBC: BlkCipherEnc,
564{
565 outbound: CryptState<EtBC, PrfBC>,
567 inbound: CryptState<EtBC, PrfBC>,
569 binding: CircuitBinding,
571}
572
573impl<EtBC, PrfBC> CryptInit for CryptStatePair<EtBC, PrfBC>
574where
575 EtBC: BlkCipher,
576 PrfBC: BlkCipherEnc,
577{
578 fn seed_len() -> usize {
579 CryptState::<EtBC, PrfBC>::seed_len() * 2 + crate::crypto::binding::CIRC_BINDING_LEN
580 }
581 fn initialize(seed: &[u8]) -> crate::Result<Self> {
582 const {
583 assert!(EtBC::KEY_LEN == PrfBC::KEY_LEN);
585 }
586 if seed.len() != Self::seed_len() {
587 return Err(internal!("Invalid seed length").into());
588 }
589 let slen = CryptState::<EtBC, PrfBC>::seed_len();
590 let (outb, inb, binding) = (&seed[0..slen], &seed[slen..slen * 2], &seed[slen * 2..]);
591 Ok(Self {
592 outbound: CryptState::initialize(outb)?,
593 inbound: CryptState::initialize(inb)?,
594 binding: binding.try_into().expect("Invalid slice length"),
595 })
596 }
597}
598
599impl<EtBC, PrfBC> super::ClientLayer<ClientOutbound<EtBC, PrfBC>, ClientInbound<EtBC, PrfBC>>
600 for CryptStatePair<EtBC, PrfBC>
601where
602 EtBC: BlkCipherDec,
603 PrfBC: BlkCipherEnc,
604{
605 fn split_client_layer(
606 self,
607 ) -> (
608 ClientOutbound<EtBC, PrfBC>,
609 ClientInbound<EtBC, PrfBC>,
610 CircuitBinding,
611 ) {
612 (self.outbound.into(), self.inbound.into(), self.binding)
613 }
614}
615
616impl<EtBC, PrfBC> super::RelayLayer<RelayOutbound<EtBC, PrfBC>, RelayInbound<EtBC, PrfBC>>
617 for CryptStatePair<EtBC, PrfBC>
618where
619 EtBC: BlkCipherEnc,
620 PrfBC: BlkCipherEnc,
621{
622 fn split_relay_layer(
623 self,
624 ) -> (
625 RelayOutbound<EtBC, PrfBC>,
626 RelayInbound<EtBC, PrfBC>,
627 CircuitBinding,
628 ) {
629 (self.outbound.into(), self.inbound.into(), self.binding)
630 }
631}
632
633#[cfg(feature = "bench")]
635pub mod bench_utils {
636 pub use super::ClientInbound;
637 pub use super::ClientOutbound;
638 pub use super::CryptStatePair;
639 pub use super::RelayInbound;
640 pub use super::RelayOutbound;
641
642 pub const CGO_THROUGHPUT: u64 = 488;
644}
645
646#[cfg(test)]
647mod test {
648 #![allow(clippy::bool_assert_comparison)]
650 #![allow(clippy::clone_on_copy)]
651 #![allow(clippy::dbg_macro)]
652 #![allow(clippy::mixed_attributes_style)]
653 #![allow(clippy::print_stderr)]
654 #![allow(clippy::print_stdout)]
655 #![allow(clippy::single_char_pattern)]
656 #![allow(clippy::unwrap_used)]
657 #![allow(clippy::unchecked_duration_subtraction)]
658 #![allow(clippy::useless_vec)]
659 #![allow(clippy::needless_pass_by_value)]
660 use crate::crypto::cell::{
663 InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
664 };
665
666 use super::*;
667 use hex_literal::hex;
668 use rand::Rng as _;
669 use tor_basic_utils::test_rng::testing_rng;
670
671 #[test]
672 fn testvec_xor() {
673 let mut b: [u8; 20] = *b"turning and turning ";
674 let s = b"in the widening gyre";
675 xor_into(&mut b, s);
676 assert_eq!(b[..], hex!("1d1b521a010b4757080a014e1d1b154e0e171545"));
677 }
678
679 #[test]
680 fn testvec_polyval() {
681 use polyval::Polyval;
682 use polyval::universal_hash::{KeyInit, UniversalHash};
683
684 let h = hex!("25629347589242761d31f826ba4b757b");
686 let x_1 = hex!("4f4f95668c83dfb6401762bb2d01a262");
687 let x_2 = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
688
689 let mut hash = Polyval::new(&h.into());
690 hash.update(&[x_1.into(), x_2.into()]);
691 let result: [u8; 16] = hash.finalize().into();
692 assert_eq!(result, hex!("f7a3b47b846119fae5b7866cf5e5b77e"));
693 }
694
695 #[allow(non_upper_case_globals)]
697 const False: bool = false;
698 #[allow(non_upper_case_globals)]
699 const True: bool = true;
700 include!("../../../testdata/cgo_et.rs");
701 include!("../../../testdata/cgo_prf.rs");
702 include!("../../../testdata/cgo_uiv.rs");
703 include!("../../../testdata/cgo_relay.rs");
704 include!("../../../testdata/cgo_client.rs");
705
706 fn unhex<const N: usize>(s: &str) -> [u8; N] {
708 hex::decode(s).unwrap().try_into().unwrap()
709 }
710
711 #[test]
712 fn testvec_et() {
713 for (encrypt, keys, tweak, input, expect_output) in ET_TEST_VECTORS {
714 let keys: [u8; 32] = unhex(keys);
715 let tweak: [u8; et::TLEN_ET] = unhex(tweak);
716 let mut block: [u8; 16] = unhex(input);
717 let expect_output: [u8; 16] = unhex(expect_output);
718 let et: et::EtCipher<Aes128> = et::EtCipher::initialize(&keys).unwrap();
719 let tweak = (
720 tweak[0..16].try_into().unwrap(),
721 tweak[16],
722 &tweak[17..].try_into().unwrap(),
723 );
724 if *encrypt {
725 et.encrypt(tweak, &mut block);
726 } else {
727 et.decrypt(tweak, &mut block);
728 }
729 assert_eq!(block, expect_output);
730 }
731 }
732
733 #[test]
734 fn testvec_prf() {
735 for (keys, offset, tweak, expect_output) in PRF_TEST_VECTORS {
736 let keys: [u8; 32] = unhex(keys);
737 assert!([0, 1].contains(offset));
738 let tweak: [u8; 16] = unhex(tweak);
739 let expect_output = hex::decode(expect_output).unwrap();
740 let prf: prf::Prf<Aes128> = prf::Prf::initialize(&keys).unwrap();
741 if *offset == 0 {
742 assert_eq!(expect_output.len(), CGO_PAYLOAD_LEN);
743 let mut data = [0_u8; CGO_PAYLOAD_LEN];
744 prf.xor_n0_stream(&tweak, &mut data);
745 assert_eq!(expect_output[..], data[..]);
746 } else {
747 let data = prf.get_n1_stream(&tweak, expect_output.len());
748 assert_eq!(expect_output[..], data[..]);
749 }
750 }
751 }
752
753 #[test]
754 fn testvec_uiv() {
755 for (encrypt, keys, tweak, left, right, (expect_left, expect_right)) in UIV_TEST_VECTORS {
756 let keys: [u8; 64] = unhex(keys);
757 let tweak: [u8; 17] = unhex(tweak);
758 let mut cell: [u8; 509] = unhex(&format!("{left}{right}"));
759 let expected: [u8; 509] = unhex(&format!("{expect_left}{expect_right}"));
760
761 let uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
762 let htweak = (tweak[0..16].try_into().unwrap(), tweak[16]);
763 if *encrypt {
764 uiv.encrypt(htweak, &mut cell);
765 } else {
766 uiv.decrypt(htweak, &mut cell);
767 }
768 assert_eq!(cell, expected);
769 }
770 }
771
772 #[test]
773 fn testvec_uiv_update() {
774 let mut rng = testing_rng();
775
776 for (keys, nonce, (expect_keys, expect_nonce)) in UIV_UPDATE_TEST_VECTORS {
777 let keys: [u8; 64] = unhex(keys);
778 let mut nonce: [u8; 16] = unhex(nonce);
779 let mut uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
780 let expect_keys: [u8; 64] = unhex(expect_keys);
781 let expect_nonce: [u8; 16] = unhex(expect_nonce);
782 uiv.update(&mut nonce);
783 assert_eq!(&nonce, &expect_nonce);
784 assert_eq!(&uiv.keys[..], &expect_keys[..]);
785
786 let uiv2: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&uiv.keys[..]).unwrap();
789
790 let tweak: [u8; 16] = rng.random();
791 let cmd = rng.random();
792 let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
793 let mut msg2 = msg1.clone();
794
795 uiv.encrypt((&tweak, cmd), &mut msg1);
796 uiv2.encrypt((&tweak, cmd), &mut msg2);
797 }
798 }
799
800 #[test]
801 fn testvec_cgo_relay() {
802 for (inbound, (k, n, tprime), ad, t, c, output) in CGO_RELAY_TEST_VECTORS {
803 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
804 let tprime: [u8; 16] = unhex(tprime);
805 let ad: [u8; 1] = unhex(ad);
806 let msg: [u8; CELL_DATA_LEN] = unhex(&format!("{t}{c}"));
807 let mut msg = RelayCellBody(Box::new(msg));
808
809 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
810 *state.tag = tprime;
811 let state = if *inbound {
812 let mut s = RelayInbound::from(state);
813 s.encrypt_inbound(ad[0].into(), &mut msg);
814 s.0
815 } else {
816 let mut s = RelayOutbound::from(state);
817 s.decrypt_outbound(ad[0].into(), &mut msg);
818 s.0
819 };
820
821 let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
823 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
824 let ex_k: [u8; 64] = unhex(ex_k);
825 let ex_n: [u8; 16] = unhex(ex_n);
826 let ex_tprime: [u8; 16] = unhex(ex_tprime);
827 assert_eq!(&ex_msg[..], &msg.0[..]);
828 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
829 assert_eq!(&state.nonce[..], &ex_n[..]);
830 assert_eq!(&state.tag[..], &ex_tprime[..]);
831 }
832 }
833
834 #[test]
835 fn testvec_cgo_relay_originate() {
836 for ((k, n, tprime), ad, m, output) in CGO_RELAY_ORIGINATE_TEST_VECTORS {
837 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
838 let tprime: [u8; 16] = unhex(tprime);
839 let ad: [u8; 1] = unhex(ad);
840 let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
841 let mut msg = [0_u8; CELL_DATA_LEN];
842 msg[16..].copy_from_slice(&msg_body[..]);
843 let mut msg = RelayCellBody(Box::new(msg));
844
845 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
846 *state.tag = tprime;
847 let mut state = RelayInbound::from(state);
848 state.originate(ad[0].into(), &mut msg);
849 let state = state.0;
850
851 let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
852 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
853 let ex_k: [u8; 64] = unhex(ex_k);
854 let ex_n: [u8; 16] = unhex(ex_n);
855 let ex_tprime: [u8; 16] = unhex(ex_tprime);
856 assert_eq!(&ex_msg[..], &msg.0[..]);
857 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
858 assert_eq!(&state.nonce[..], &ex_n[..]);
859 assert_eq!(&state.tag[..], &ex_tprime[..]);
860 }
861 }
862
863 #[test]
864 fn testvec_cgo_client_originate() {
865 for (ss, hop, ad, m, output) in CGO_CLIENT_ORIGINATE_TEST_VECTORS {
866 assert!(*hop > 0); let mut client = OutboundClientCrypt::new();
868 let mut individual_layers = Vec::new();
869 for (k, n, tprime) in ss {
870 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
871 let tprime: [u8; 16] = unhex(tprime);
872 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
873 *state.tag = tprime;
874 client.add_layer(Box::new(ClientOutbound::from(state.clone())));
875 individual_layers.push(ClientOutbound::from(state));
876 }
877
878 let ad: [u8; 1] = unhex(ad);
879 let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
880 let mut msg = [0_u8; CELL_DATA_LEN];
881 msg[16..].copy_from_slice(&msg_body[..]);
882 let mut msg = RelayCellBody(Box::new(msg));
883 let mut msg2 = msg.clone();
884
885 client
887 .encrypt(ad[0].into(), &mut msg, (*hop - 1).into())
888 .unwrap();
889 {
893 let hop_idx = usize::from(*hop) - 1;
894 individual_layers[hop_idx].originate_for(ad[0].into(), &mut msg2);
895 for idx in (0..hop_idx).rev() {
896 individual_layers[idx].encrypt_outbound(ad[0].into(), &mut msg2);
897 }
898 }
899 assert_eq!(&msg.0[..], &msg2.0[..]);
900
901 let (ex_ss, (ex_t, ex_c)) = output;
902 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
903 assert_eq!(&ex_msg[..], &msg.0[..]);
904
905 for (layer, (ex_k, ex_n, ex_tprime)) in individual_layers.iter().zip(ex_ss.iter()) {
906 let state = &layer.0;
907 let ex_k: [u8; 64] = unhex(ex_k);
908 let ex_n: [u8; 16] = unhex(ex_n);
909 let ex_tprime: [u8; 16] = unhex(ex_tprime);
910
911 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
912 assert_eq!(&state.nonce[..], &ex_n[..]);
913 assert_eq!(&state.tag[..], &ex_tprime);
914 }
915 }
916 }
917}