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