1#![allow(dead_code)] use aes::{Aes128, Aes128Dec, Aes128Enc, Aes256, Aes256Dec, Aes256Enc};
22use cipher::common::array::Array;
23use cipher::{BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, KeyInit, StreamCipher as _};
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: KeyInit + BlockSizeUser<BlockSize = BlockLen> + Clone {
63 const KEY_LEN: usize;
65}
66
67#[cfg_attr(feature = "bench", visibility::make(pub))]
72pub(crate) trait BlkCipherEnc: BlkCipher + BlockCipherEncrypt {}
73
74#[cfg_attr(feature = "bench", visibility::make(pub))]
79pub(crate) trait BlkCipherDec: BlkCipher + BlockCipherDecrypt {}
80
81impl BlkCipher for Aes128 {
82 const KEY_LEN: usize = 16;
83}
84impl BlkCipherEnc for Aes128 {}
85impl BlkCipherDec for Aes128 {}
86impl BlkCipher for Aes128Enc {
87 const KEY_LEN: usize = 16;
88}
89impl BlkCipherEnc for Aes128Enc {}
90impl BlkCipher for Aes128Dec {
91 const KEY_LEN: usize = 16;
92}
93impl BlkCipherDec for Aes128Dec {}
94
95impl BlkCipher for Aes256 {
96 const KEY_LEN: usize = 32;
97}
98impl BlkCipherEnc for Aes256 {}
99impl BlkCipherDec for Aes256 {}
100impl BlkCipher for Aes256Enc {
101 const KEY_LEN: usize = 32;
102}
103impl BlkCipherEnc for Aes256Enc {}
104impl BlkCipher for Aes256Dec {
105 const KEY_LEN: usize = 32;
106}
107impl BlkCipherDec for Aes256Dec {}
108
109mod et {
111 use super::*;
112
113 pub(super) type EtTweak<'a> = (&'a [u8; CGO_TAG_LEN], u8, &'a [u8; CGO_PAYLOAD_LEN]);
118 pub(super) const TLEN_ET: usize = CGO_TAG_LEN + 1 + CGO_PAYLOAD_LEN;
120
121 #[derive(Clone)]
127 pub(super) struct EtCipher<BC: BlkCipher> {
128 kb: BC,
130 ku: Polyval,
132 }
133 impl<BC: BlkCipher> EtCipher<BC> {
134 fn compute_tweak_hash(&self, tweak: EtTweak<'_>) -> Zeroizing<Block> {
137 let mut ku = self.ku.clone();
140
141 let mut block1 = Zeroizing::new([0_u8; 16]);
142 block1[0] = tweak.1;
143 block1[1..16].copy_from_slice(&tweak.2[0..15]);
144 ku.update(&[(*tweak.0).into(), (*block1).into()]);
145 ku.update_padded(&tweak.2[15..]);
146 Zeroizing::new(ku.finalize().into())
147 }
148 }
149 impl<BC: BlkCipherEnc> EtCipher<BC> {
150 pub(super) fn encrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
152 let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
154 xor_into(block, &tag);
155 self.kb.encrypt_block(block.into());
156 xor_into(block, &tag);
157 }
158 }
159 impl<BC: BlkCipherDec> EtCipher<BC> {
160 pub(super) fn decrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
162 let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
164 xor_into(block, &tag);
165 self.kb.decrypt_block(block.into());
166 xor_into(block, &tag);
167 }
168 }
169 impl<BC: BlkCipher> CryptInit for EtCipher<BC> {
170 fn seed_len() -> usize {
171 BC::key_size() + polyval::KEY_SIZE
172 }
173 fn initialize(seed: &[u8]) -> crate::Result<Self> {
174 if seed.len() != Self::seed_len() {
177 return Err(internal!("Invalid seed length").into());
178 }
179 let (kb, ku) = seed.split_at(BC::key_size());
180 let kb: &Array<_, _> = kb
181 .try_into()
182 .expect("Incorrect key size, even though it was validated!?");
183 let ku: &[u8; 16] = ku
184 .try_into()
185 .expect("Incorrect key size, even though it was validated!?");
186 Ok(Self {
187 kb: BC::new(kb),
188 ku: Polyval::new(ku.into()),
189 })
190 }
191 }
192}
193
194mod prf {
196 use tor_error::internal;
197
198 use super::*;
199
200 type PrfTweak = [u8; 16];
202 const PRF_N0_LEN: usize = CGO_PAYLOAD_LEN;
204 const PRF_N1_OFFSET: usize = 31 * 16;
206 const _: () = assert!(PRF_N1_OFFSET >= PRF_N0_LEN);
207
208 #[derive(Clone)]
213 pub(super) struct Prf<BC: BlkCipherEnc> {
214 k: BC,
216 b: Polyval,
218 }
219 impl<BC: BlkCipherEnc> Prf<BC> {
220 fn cipher(&self, tweak: &PrfTweak, t: bool) -> ctr::Ctr128BE<BC> {
223 use {
224 cipher::{InnerIvInit as _, StreamCipherSeek as _},
225 ctr::CtrCore,
226 };
227 let mut b = self.b.clone(); b.update(&[(*tweak).into()]);
229 let mut iv = b.finalize();
230 *iv.last_mut().expect("no last element?") &= 0xC0; let iv: [u8; 16] = iv.into(); let mut cipher: ctr::Ctr128BE<BC> = cipher::StreamCipherCoreWrapper::from_core(
233 CtrCore::inner_iv_init(self.k.clone(), (&iv).into()),
234 );
235 if t {
236 debug_assert_eq!(cipher.current_pos::<u32>(), 0_u32);
237 cipher.seek(PRF_N1_OFFSET);
238 }
239
240 cipher
241 }
242
243 pub(super) fn xor_n0_stream(&self, tweak: &PrfTweak, out: &mut [u8; PRF_N0_LEN]) {
246 let mut stream = self.cipher(tweak, false);
247 stream.apply_keystream(out);
248 }
249
250 pub(super) fn get_n1_stream(&self, tweak: &PrfTweak, n: usize) -> Zeroizing<Vec<u8>> {
253 let mut output = Zeroizing::new(vec![0_u8; n]);
254 self.cipher(tweak, true).apply_keystream(output.as_mut());
255 output
256 }
257 }
258
259 impl<BC: BlkCipherEnc> CryptInit for Prf<BC> {
260 fn seed_len() -> usize {
261 BC::key_size() + polyval::KEY_SIZE
262 }
263 fn initialize(seed: &[u8]) -> crate::Result<Self> {
264 if seed.len() != Self::seed_len() {
265 return Err(internal!("Invalid seed length").into());
266 }
267 let (k, b) = seed.split_at(BC::key_size());
268 let k: &Array<_, _> = k
269 .try_into()
270 .expect("Incorrect key size, even though it was validated!?");
271
272 let b: &[u8; 16] = b
273 .try_into()
274 .expect("Incorrect key size, even though it was validated!?");
275 Ok(Self {
276 k: BC::new(k),
277 b: Polyval::new(b.into()),
278 })
279 }
280 }
281}
282
283mod uiv {
287 use super::*;
288
289 pub(super) type UivTweak<'a> = (&'a [u8; BLK_LEN], u8);
291
292 #[derive(Clone)]
294 pub(super) struct Uiv<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
295 j: et::EtCipher<EtBC>,
297 s: prf::Prf<PrfBC>,
299
300 #[cfg(test)]
305 pub(super) keys: Zeroizing<Vec<u8>>,
306 }
307
308 fn split(
311 cell_body: &mut [u8; CELL_DATA_LEN],
312 ) -> (&mut [u8; CGO_TAG_LEN], &mut [u8; CGO_PAYLOAD_LEN]) {
313 let (left, right) = cell_body.split_at_mut(CGO_TAG_LEN);
315 (
316 left.try_into().expect("split_at_mut returned wrong size!"),
317 right.try_into().expect("split_at_mut returned wrong size!"),
318 )
319 }
320
321 impl<EtBC: BlkCipherEnc, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
322 pub(super) fn encrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
326 let (left, right) = split(cell_body);
331 self.j.encrypt((tweak.0, tweak.1, right), left);
332 self.s.xor_n0_stream(left, right);
333 }
334 }
335 impl<EtBC: BlkCipherDec, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
336 pub(super) fn decrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
340 let (left, right) = split(cell_body);
345 self.s.xor_n0_stream(left, right);
346 self.j.decrypt((tweak.0, tweak.1, right), left);
347 }
348 }
349 impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
350 pub(super) fn update(&mut self, nonce: &mut [u8; BLK_LEN]) {
355 let n_bytes = Self::seed_len() + BLK_LEN;
363 let seed = self.s.get_n1_stream(nonce, n_bytes);
364 #[cfg(test)]
365 {
366 self.keys = Zeroizing::new(seed[..Self::seed_len()].to_vec());
367 }
368 let (j, s, n) = Self::split_seed(&seed);
369 self.j = et::EtCipher::initialize(j).expect("Invalid slice len");
370 self.s = prf::Prf::initialize(s).expect("invalid slice len");
371 nonce[..].copy_from_slice(n);
372 }
373
374 fn split_seed(seed: &[u8]) -> (&[u8], &[u8], &[u8]) {
376 let len_j = et::EtCipher::<EtBC>::seed_len();
377 let len_s = prf::Prf::<PrfBC>::seed_len();
378 (
379 &seed[0..len_j],
380 &seed[len_j..len_j + len_s],
381 &seed[len_j + len_s..],
382 )
383 }
384 }
385
386 impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for Uiv<EtBC, PrfBC> {
387 fn seed_len() -> usize {
388 super::et::EtCipher::<EtBC>::seed_len() + super::prf::Prf::<PrfBC>::seed_len()
389 }
390 fn initialize(seed: &[u8]) -> crate::Result<Self> {
391 if seed.len() != Self::seed_len() {
392 return Err(internal!("Invalid seed length").into());
393 }
394 #[cfg(test)]
395 let keys = Zeroizing::new(seed.to_vec());
396 let (j, s, n) = Self::split_seed(seed);
397 debug_assert!(n.is_empty());
398 Ok(Self {
399 j: et::EtCipher::initialize(j)?,
400 s: prf::Prf::initialize(s)?,
401 #[cfg(test)]
402 keys,
403 })
404 }
405 }
406}
407
408fn xor_into<const N: usize>(output: &mut [u8; N], input: &[u8; N]) {
410 for i in 0..N {
411 output[i] ^= input[i];
412 }
413}
414
415#[inline]
420fn first_block(bytes: &[u8]) -> &[u8; BLK_LEN] {
421 bytes[0..BLK_LEN].try_into().expect("Slice too short!")
422}
423
424#[derive(Clone)]
426struct CryptState<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
427 uiv: uiv::Uiv<EtBC, PrfBC>,
429 nonce: Zeroizing<[u8; BLK_LEN]>,
431 tag: Zeroizing<[u8; BLK_LEN]>,
433}
434
435impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for CryptState<EtBC, PrfBC> {
436 fn seed_len() -> usize {
437 uiv::Uiv::<EtBC, PrfBC>::seed_len() + BLK_LEN
438 }
439 fn initialize(seed: &[u8]) -> crate::Result<Self> {
441 if seed.len() != Self::seed_len() {
442 return Err(internal!("Invalid seed length").into());
443 }
444 let (j_s, n) = seed.split_at(uiv::Uiv::<EtBC, PrfBC>::seed_len());
445 Ok(Self {
446 uiv: uiv::Uiv::initialize(j_s)?,
447 nonce: Zeroizing::new(n.try_into().expect("invalid splice length")),
448 tag: Zeroizing::new([0; BLK_LEN]),
449 })
450 }
451}
452
453#[cfg_attr(feature = "bench", visibility::make(pub))]
455#[derive(Clone, derive_more::From)]
456pub(crate) struct ClientOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
457where
458 EtBC: BlkCipherDec,
459 PrfBC: BlkCipherEnc;
460impl<EtBC, PrfBC> super::OutboundClientLayer for ClientOutbound<EtBC, PrfBC>
461where
462 EtBC: BlkCipherDec,
463 PrfBC: BlkCipherEnc,
464{
465 fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
466 cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
467 self.encrypt_outbound(cmd, cell);
468 self.0.uiv.update(&mut self.0.nonce);
469 SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Block length not a valid sendme tag.")
470 }
471 fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
472 let t_new: [u8; BLK_LEN] = *first_block(&*cell.0);
474
475 self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
478 *self.0.tag = t_new;
479 }
480}
481
482#[cfg_attr(feature = "bench", visibility::make(pub))]
484#[derive(Clone, derive_more::From)]
485pub(crate) struct ClientInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
486where
487 EtBC: BlkCipherDec,
488 PrfBC: BlkCipherEnc;
489impl<EtBC, PrfBC> super::InboundClientLayer for ClientInbound<EtBC, PrfBC>
490where
491 EtBC: BlkCipherDec,
492 PrfBC: BlkCipherEnc,
493{
494 fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
495 let mut t_orig: [u8; BLK_LEN] = *first_block(&*cell.0);
496 self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
501 *self.0.tag = t_orig;
502 if ct::bytes_eq(&cell.0[..CGO_TAG_LEN], &self.0.nonce[..]) {
503 self.0.uiv.update(&mut t_orig);
504 *self.0.nonce = t_orig;
505 Some((*self.0.tag).into())
507 } else {
508 None
509 }
510 }
511}
512
513#[cfg_attr(feature = "bench", visibility::make(pub))]
515#[derive(Clone, derive_more::From)]
516pub(crate) struct RelayOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
517where
518 EtBC: BlkCipherEnc,
519 PrfBC: BlkCipherEnc;
520impl<EtBC, PrfBC> super::OutboundRelayLayer for RelayOutbound<EtBC, PrfBC>
521where
522 EtBC: BlkCipherEnc,
523 PrfBC: BlkCipherEnc,
524{
525 fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
526 let tag = SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Invalid sendme length");
527 self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
530 *self.0.tag = *first_block(&*cell.0);
531 if ct::bytes_eq(self.0.tag.as_ref(), &self.0.nonce[..]) {
532 self.0.uiv.update(&mut self.0.nonce);
533 Some(tag)
534 } else {
535 None
536 }
537 }
538}
539
540#[cfg_attr(feature = "bench", visibility::make(pub))]
542#[derive(Clone, derive_more::From)]
543pub(crate) struct RelayInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
544where
545 EtBC: BlkCipherEnc,
546 PrfBC: BlkCipherEnc;
547impl<EtBC, PrfBC> super::InboundRelayLayer for RelayInbound<EtBC, PrfBC>
548where
549 EtBC: BlkCipherEnc,
550 PrfBC: BlkCipherEnc,
551{
552 fn originate(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
553 cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
554 self.encrypt_inbound(cmd, cell);
555 self.0.nonce.copy_from_slice(&cell.0[0..BLK_LEN]);
556 self.0.uiv.update(&mut self.0.nonce);
557 (*self.0.tag).into()
559 }
560 fn encrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
561 self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
564 *self.0.tag = *first_block(&*cell.0);
565 }
566}
567
568#[cfg_attr(feature = "bench", visibility::make(pub))]
571#[derive(Clone)]
572pub(crate) struct CryptStatePair<EtBC, PrfBC>
573where
574 EtBC: BlkCipher,
575 PrfBC: BlkCipherEnc,
576{
577 outbound: CryptState<EtBC, PrfBC>,
579 inbound: CryptState<EtBC, PrfBC>,
581 binding: CircuitBinding,
583}
584
585impl<EtBC, PrfBC> CryptInit for CryptStatePair<EtBC, PrfBC>
586where
587 EtBC: BlkCipher,
588 PrfBC: BlkCipherEnc,
589{
590 fn seed_len() -> usize {
591 CryptState::<EtBC, PrfBC>::seed_len() * 2 + crate::crypto::binding::CIRC_BINDING_LEN
592 }
593 fn initialize(seed: &[u8]) -> crate::Result<Self> {
594 const {
595 assert!(EtBC::KEY_LEN == PrfBC::KEY_LEN);
597 }
598 if seed.len() != Self::seed_len() {
599 return Err(internal!("Invalid seed length").into());
600 }
601 let slen = CryptState::<EtBC, PrfBC>::seed_len();
602 let (outb, inb, binding) = (&seed[0..slen], &seed[slen..slen * 2], &seed[slen * 2..]);
603 Ok(Self {
604 outbound: CryptState::initialize(outb)?,
605 inbound: CryptState::initialize(inb)?,
606 binding: binding.try_into().expect("Invalid slice length"),
607 })
608 }
609}
610
611impl<EtBC, PrfBC> super::ClientLayer<ClientOutbound<EtBC, PrfBC>, ClientInbound<EtBC, PrfBC>>
612 for CryptStatePair<EtBC, PrfBC>
613where
614 EtBC: BlkCipherDec,
615 PrfBC: BlkCipherEnc,
616{
617 fn split_client_layer(
618 self,
619 ) -> (
620 ClientOutbound<EtBC, PrfBC>,
621 ClientInbound<EtBC, PrfBC>,
622 CircuitBinding,
623 ) {
624 (self.outbound.into(), self.inbound.into(), self.binding)
625 }
626}
627
628impl<EtBC, PrfBC> super::RelayLayer<RelayOutbound<EtBC, PrfBC>, RelayInbound<EtBC, PrfBC>>
629 for CryptStatePair<EtBC, PrfBC>
630where
631 EtBC: BlkCipherEnc,
632 PrfBC: BlkCipherEnc,
633{
634 fn split_relay_layer(
635 self,
636 ) -> (
637 RelayOutbound<EtBC, PrfBC>,
638 RelayInbound<EtBC, PrfBC>,
639 CircuitBinding,
640 ) {
641 (self.outbound.into(), self.inbound.into(), self.binding)
642 }
643}
644
645#[cfg(feature = "bench")]
647pub mod bench_utils {
648 pub use super::ClientInbound;
649 pub use super::ClientOutbound;
650 pub use super::CryptStatePair;
651 pub use super::RelayInbound;
652 pub use super::RelayOutbound;
653
654 pub const CGO_THROUGHPUT: u64 = 488;
656}
657
658#[cfg(test)]
659mod test {
660 #![allow(clippy::bool_assert_comparison)]
662 #![allow(clippy::clone_on_copy)]
663 #![allow(clippy::dbg_macro)]
664 #![allow(clippy::mixed_attributes_style)]
665 #![allow(clippy::print_stderr)]
666 #![allow(clippy::print_stdout)]
667 #![allow(clippy::single_char_pattern)]
668 #![allow(clippy::unwrap_used)]
669 #![allow(clippy::unchecked_time_subtraction)]
670 #![allow(clippy::useless_vec)]
671 #![allow(clippy::needless_pass_by_value)]
672 #![allow(clippy::string_slice)] use crate::crypto::cell::{
676 InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
677 };
678
679 use super::*;
680 use hex_literal::hex;
681 use rand::RngExt as _;
682 use tor_basic_utils::test_rng::testing_rng;
683
684 #[test]
685 fn testvec_xor() {
686 let mut b: [u8; 20] = *b"turning and turning ";
687 let s = b"in the widening gyre";
688 xor_into(&mut b, s);
689 assert_eq!(b[..], hex!("1d1b521a010b4757080a014e1d1b154e0e171545"));
690 }
691
692 #[test]
693 fn testvec_polyval() {
694 use polyval::Polyval;
695 use polyval::universal_hash::UniversalHash;
696
697 let h = hex!("25629347589242761d31f826ba4b757b");
699 let x_1 = hex!("4f4f95668c83dfb6401762bb2d01a262");
700 let x_2 = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
701
702 let mut hash = Polyval::new(&h.into());
703 hash.update(&[x_1.into(), x_2.into()]);
704 let result: [u8; 16] = hash.finalize().into();
705 assert_eq!(result, hex!("f7a3b47b846119fae5b7866cf5e5b77e"));
706 }
707
708 #[allow(non_upper_case_globals)]
710 const False: bool = false;
711 #[allow(non_upper_case_globals)]
712 const True: bool = true;
713 include!("../../../testdata/cgo_et.rs");
714 include!("../../../testdata/cgo_prf.rs");
715 include!("../../../testdata/cgo_uiv.rs");
716 include!("../../../testdata/cgo_relay.rs");
717 include!("../../../testdata/cgo_client.rs");
718
719 fn unhex<const N: usize>(s: &str) -> [u8; N] {
721 hex::decode(s).unwrap().try_into().unwrap()
722 }
723
724 #[test]
725 fn testvec_et() {
726 for (encrypt, keys, tweak, input, expect_output) in ET_TEST_VECTORS {
727 let keys: [u8; 32] = unhex(keys);
728 let tweak: [u8; et::TLEN_ET] = unhex(tweak);
729 let mut block: [u8; 16] = unhex(input);
730 let expect_output: [u8; 16] = unhex(expect_output);
731 let et: et::EtCipher<Aes128> = et::EtCipher::initialize(&keys).unwrap();
732 let tweak = (
733 tweak[0..16].try_into().unwrap(),
734 tweak[16],
735 &tweak[17..].try_into().unwrap(),
736 );
737 if *encrypt {
738 et.encrypt(tweak, &mut block);
739 } else {
740 et.decrypt(tweak, &mut block);
741 }
742 assert_eq!(block, expect_output);
743 }
744 }
745
746 #[test]
747 fn testvec_prf() {
748 for (keys, offset, tweak, expect_output) in PRF_TEST_VECTORS {
749 let keys: [u8; 32] = unhex(keys);
750 assert!([0, 1].contains(offset));
751 let tweak: [u8; 16] = unhex(tweak);
752 let expect_output = hex::decode(expect_output).unwrap();
753 let prf: prf::Prf<Aes128> = prf::Prf::initialize(&keys).unwrap();
754 if *offset == 0 {
755 assert_eq!(expect_output.len(), CGO_PAYLOAD_LEN);
756 let mut data = [0_u8; CGO_PAYLOAD_LEN];
757 prf.xor_n0_stream(&tweak, &mut data);
758 assert_eq!(expect_output[..], data[..]);
759 } else {
760 let data = prf.get_n1_stream(&tweak, expect_output.len());
761 assert_eq!(expect_output[..], data[..]);
762 }
763 }
764 }
765
766 #[test]
767 fn testvec_uiv() {
768 for (encrypt, keys, tweak, left, right, (expect_left, expect_right)) in UIV_TEST_VECTORS {
769 let keys: [u8; 64] = unhex(keys);
770 let tweak: [u8; 17] = unhex(tweak);
771 let mut cell: [u8; 509] = unhex(&format!("{left}{right}"));
772 let expected: [u8; 509] = unhex(&format!("{expect_left}{expect_right}"));
773
774 let uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
775 let htweak = (tweak[0..16].try_into().unwrap(), tweak[16]);
776 if *encrypt {
777 uiv.encrypt(htweak, &mut cell);
778 } else {
779 uiv.decrypt(htweak, &mut cell);
780 }
781 assert_eq!(cell, expected);
782 }
783 }
784
785 #[test]
786 fn testvec_uiv_update() {
787 let mut rng = testing_rng();
788
789 for (keys, nonce, (expect_keys, expect_nonce)) in UIV_UPDATE_TEST_VECTORS {
790 let keys: [u8; 64] = unhex(keys);
791 let mut nonce: [u8; 16] = unhex(nonce);
792 let mut uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
793 let expect_keys: [u8; 64] = unhex(expect_keys);
794 let expect_nonce: [u8; 16] = unhex(expect_nonce);
795 uiv.update(&mut nonce);
796 assert_eq!(&nonce, &expect_nonce);
797 assert_eq!(&uiv.keys[..], &expect_keys[..]);
798
799 let uiv2: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&uiv.keys[..]).unwrap();
802
803 let tweak: [u8; 16] = rng.random();
804 let cmd = rng.random();
805 let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
806 let mut msg2 = msg1.clone();
807
808 uiv.encrypt((&tweak, cmd), &mut msg1);
809 uiv2.encrypt((&tweak, cmd), &mut msg2);
810 }
811 }
812
813 #[test]
814 fn testvec_cgo_relay() {
815 for (inbound, (k, n, tprime), ad, t, c, output) in CGO_RELAY_TEST_VECTORS {
816 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
817 let tprime: [u8; 16] = unhex(tprime);
818 let ad: [u8; 1] = unhex(ad);
819 let msg: [u8; CELL_DATA_LEN] = unhex(&format!("{t}{c}"));
820 let mut msg = RelayCellBody(Box::new(msg));
821
822 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
823 *state.tag = tprime;
824 let state = if *inbound {
825 let mut s = RelayInbound::from(state);
826 s.encrypt_inbound(ad[0].into(), &mut msg);
827 s.0
828 } else {
829 let mut s = RelayOutbound::from(state);
830 s.decrypt_outbound(ad[0].into(), &mut msg);
831 s.0
832 };
833
834 let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
836 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
837 let ex_k: [u8; 64] = unhex(ex_k);
838 let ex_n: [u8; 16] = unhex(ex_n);
839 let ex_tprime: [u8; 16] = unhex(ex_tprime);
840 assert_eq!(&ex_msg[..], &msg.0[..]);
841 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
842 assert_eq!(&state.nonce[..], &ex_n[..]);
843 assert_eq!(&state.tag[..], &ex_tprime[..]);
844 }
845 }
846
847 #[test]
848 fn testvec_cgo_relay_originate() {
849 for ((k, n, tprime), ad, m, output) in CGO_RELAY_ORIGINATE_TEST_VECTORS {
850 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
851 let tprime: [u8; 16] = unhex(tprime);
852 let ad: [u8; 1] = unhex(ad);
853 let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
854 let mut msg = [0_u8; CELL_DATA_LEN];
855 msg[16..].copy_from_slice(&msg_body[..]);
856 let mut msg = RelayCellBody(Box::new(msg));
857
858 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
859 *state.tag = tprime;
860 let mut state = RelayInbound::from(state);
861 state.originate(ad[0].into(), &mut msg);
862 let state = state.0;
863
864 let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
865 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
866 let ex_k: [u8; 64] = unhex(ex_k);
867 let ex_n: [u8; 16] = unhex(ex_n);
868 let ex_tprime: [u8; 16] = unhex(ex_tprime);
869 assert_eq!(&ex_msg[..], &msg.0[..]);
870 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
871 assert_eq!(&state.nonce[..], &ex_n[..]);
872 assert_eq!(&state.tag[..], &ex_tprime[..]);
873 }
874 }
875
876 #[test]
877 fn testvec_cgo_client_originate() {
878 for (ss, hop, ad, m, output) in CGO_CLIENT_ORIGINATE_TEST_VECTORS {
879 assert!(*hop > 0); let mut client = OutboundClientCrypt::new();
881 let mut individual_layers = Vec::new();
882 for (k, n, tprime) in ss {
883 let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
884 let tprime: [u8; 16] = unhex(tprime);
885 let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
886 *state.tag = tprime;
887 client.add_layer(Box::new(ClientOutbound::from(state.clone())));
888 individual_layers.push(ClientOutbound::from(state));
889 }
890
891 let ad: [u8; 1] = unhex(ad);
892 let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
893 let mut msg = [0_u8; CELL_DATA_LEN];
894 msg[16..].copy_from_slice(&msg_body[..]);
895 let mut msg = RelayCellBody(Box::new(msg));
896 let mut msg2 = msg.clone();
897
898 client
900 .encrypt(ad[0].into(), &mut msg, (*hop - 1).into())
901 .unwrap();
902 {
906 let hop_idx = usize::from(*hop) - 1;
907 individual_layers[hop_idx].originate_for(ad[0].into(), &mut msg2);
908 for idx in (0..hop_idx).rev() {
909 individual_layers[idx].encrypt_outbound(ad[0].into(), &mut msg2);
910 }
911 }
912 assert_eq!(&msg.0[..], &msg2.0[..]);
913
914 let (ex_ss, (ex_t, ex_c)) = output;
915 let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
916 assert_eq!(&ex_msg[..], &msg.0[..]);
917
918 for (layer, (ex_k, ex_n, ex_tprime)) in individual_layers.iter().zip(ex_ss.iter()) {
919 let state = &layer.0;
920 let ex_k: [u8; 64] = unhex(ex_k);
921 let ex_n: [u8; 16] = unhex(ex_n);
922 let ex_tprime: [u8; 16] = unhex(ex_tprime);
923
924 assert_eq!(&state.uiv.keys[..], &ex_k[..]);
925 assert_eq!(&state.nonce[..], &ex_n[..]);
926 assert_eq!(&state.tag[..], &ex_tprime);
927 }
928 }
929 }
930}