1#![allow(dead_code)]
14
15use std::borrow::Borrow;
16
17use super::{RelayHandshakeError, RelayHandshakeResult};
18use crate::util::ct;
19use crate::{Error, Result};
20use tor_bytes::{EncodeResult, Reader, SecretBuf, Writeable, Writer};
21use tor_error::into_internal;
22use tor_llcrypto::d::{Sha3_256, Shake256, Shake256Reader};
23use tor_llcrypto::pk::{curve25519, ed25519::Ed25519Identity};
24use tor_llcrypto::util::ct::ct_lookup;
25
26use cipher::{KeyIvInit, StreamCipher};
27
28use crate::crypto::handshake::KeyGenerator;
29use rand_core::{CryptoRng, RngCore};
30use subtle::{Choice, ConstantTimeEq};
31use tor_cell::relaycell::extend::{CircRequestExt, CircResponseExt};
32use tor_llcrypto::cipher::aes::Aes256Ctr;
33use zeroize::Zeroizing;
34
35const NTOR3_CIRC_VERIFICATION: &[u8] = b"circuit extend";
37
38const ENC_KEY_LEN: usize = 32;
40const MAC_KEY_LEN: usize = 32;
42const PUB_KEY_LEN: usize = 32;
44const DIGEST_LEN: usize = 32;
46const MAC_LEN: usize = 32;
48const ID_LEN: usize = 32;
50
51type DigestVal = [u8; DIGEST_LEN];
53type MacVal = [u8; MAC_LEN];
55type EncKey = Zeroizing<[u8; ENC_KEY_LEN]>;
59type MacKey = [u8; MAC_KEY_LEN];
61
62struct NtorV3XofReader(Shake256Reader);
64
65impl digest::XofReader for NtorV3XofReader {
66 fn read(&mut self, buffer: &mut [u8]) {
67 self.0.read(buffer);
68 }
69}
70
71struct Encap<'a>(&'a [u8]);
76
77impl<'a> Writeable for Encap<'a> {
78 fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
79 b.write_u64(self.0.len() as u64);
80 b.write(self.0)
81 }
82}
83
84impl<'a> Encap<'a> {
85 fn len(&self) -> usize {
87 self.0.len()
88 }
89 fn data(&self) -> &'a [u8] {
91 self.0
92 }
93}
94
95macro_rules! define_tweaks {
97 {
98 $(#[$pid_meta:meta])*
99 PROTOID = $protoid:expr;
100 $( $(#[$meta:meta])* $name:ident <= $suffix:expr ; )*
101 } => {
102 $(#[$pid_meta])*
103 const PROTOID: &'static [u8] = $protoid.as_bytes();
104 $(
105 $(#[$meta])*
106 const $name : Encap<'static> =
107 Encap(concat!($protoid, ":", $suffix).as_bytes());
108 )*
109 }
110}
111
112define_tweaks! {
113 PROTOID = "ntor3-curve25519-sha3_256-1";
116
117 T_MSGMAC <= "msg_mac";
120 T_MSGKDF <= "kdf_phase1";
123 T_KEY_SEED <= "key_seed";
125 T_VERIFY <= "verify";
127 T_FINAL <= "kdf_final";
130 T_AUTH <= "auth_final";
133}
134
135fn hash(t: &Encap<'_>, data: &[u8]) -> DigestVal {
137 use digest::Digest;
138 let mut d = Sha3_256::new();
139 d.update((t.len() as u64).to_be_bytes());
140 d.update(t.data());
141 d.update(data);
142 d.finalize().into()
143}
144
145fn encrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
150 let mut d = m.to_vec();
151 let zero_iv = Default::default();
152 let mut cipher = Aes256Ctr::new(key.as_ref().into(), &zero_iv);
153 cipher.apply_keystream(&mut d);
154 d
155}
156fn decrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
158 encrypt(key, m)
159}
160
161struct DigestWriter<U>(U);
164impl<U: digest::Update> tor_bytes::Writer for DigestWriter<U> {
165 fn write_all(&mut self, bytes: &[u8]) {
166 self.0.update(bytes);
167 }
168}
169impl<U> DigestWriter<U> {
170 fn take(self) -> U {
172 self.0
173 }
174}
175
176fn h_key_seed(d: &[u8]) -> DigestVal {
178 hash(&T_KEY_SEED, d)
179}
180fn h_verify(d: &[u8]) -> DigestVal {
182 hash(&T_VERIFY, d)
183}
184
185fn kdf_msgkdf(
192 xb: &curve25519::SharedSecret,
193 relay_public: &NtorV3PublicKey,
194 client_public: &curve25519::PublicKey,
195 verification: &[u8],
196) -> EncodeResult<(EncKey, DigestWriter<Sha3_256>)> {
197 use digest::{ExtendableOutput, XofReader};
201 let mut msg_kdf = DigestWriter(Shake256::default());
202 msg_kdf.write(&T_MSGKDF)?;
203 msg_kdf.write(xb)?;
204 msg_kdf.write(&relay_public.id)?;
205 msg_kdf.write(client_public)?;
206 msg_kdf.write(&relay_public.pk)?;
207 msg_kdf.write(PROTOID)?;
208 msg_kdf.write(&Encap(verification))?;
209 let mut r = msg_kdf.take().finalize_xof();
210 let mut enc_key = Zeroizing::new([0; ENC_KEY_LEN]);
211 let mut mac_key = Zeroizing::new([0; MAC_KEY_LEN]);
212
213 r.read(&mut enc_key[..]);
214 r.read(&mut mac_key[..]);
215 let mut mac = DigestWriter(Sha3_256::default());
216 {
217 mac.write(&T_MSGMAC)?;
218 mac.write(&Encap(&mac_key[..]))?;
219 mac.write(&relay_public.id)?;
220 mac.write(&relay_public.pk)?;
221 mac.write(client_public)?;
222 }
223
224 Ok((enc_key, mac))
225}
226
227pub(crate) struct NtorV3Client;
229
230impl super::ClientHandshake for NtorV3Client {
231 type KeyType = NtorV3PublicKey;
232 type StateType = NtorV3HandshakeState;
233 type KeyGen = NtorV3KeyGenerator;
234 type ClientAuxData = [CircRequestExt];
235 type ServerAuxData = Vec<CircResponseExt>;
236
237 fn client1<R: RngCore + CryptoRng, M: Borrow<[CircRequestExt]>>(
243 rng: &mut R,
244 key: &NtorV3PublicKey,
245 extensions: &M,
246 ) -> Result<(Self::StateType, Vec<u8>)> {
247 let mut message = Vec::new();
248 CircRequestExt::write_many_onto(extensions.borrow(), &mut message)
249 .map_err(|e| Error::from_bytes_enc(e, "ntor3 handshake extensions"))?;
250 Ok(
251 client_handshake_ntor_v3(rng, key, &message, NTOR3_CIRC_VERIFICATION)
252 .map_err(into_internal!("Can't encode ntor3 client handshake."))?,
253 )
254 }
255
256 fn client2<T: AsRef<[u8]>>(
261 state: Self::StateType,
262 msg: T,
263 ) -> Result<(Vec<CircResponseExt>, Self::KeyGen)> {
264 let (message, xofreader) =
265 client_handshake_ntor_v3_part2(&state, msg.as_ref(), NTOR3_CIRC_VERIFICATION)?;
266 let extensions = CircResponseExt::decode(&message).map_err(|err| Error::CellDecodeErr {
267 object: "ntor v3 extensions",
268 err,
269 })?;
270 let keygen = NtorV3KeyGenerator { reader: xofreader };
271
272 Ok((extensions, keygen))
273 }
274}
275
276pub(crate) struct NtorV3Server;
278
279impl super::ServerHandshake for NtorV3Server {
280 type KeyType = NtorV3SecretKey;
281 type KeyGen = NtorV3KeyGenerator;
282 type ClientAuxData = [CircRequestExt];
283 type ServerAuxData = Vec<CircResponseExt>;
284
285 fn server<R: RngCore + CryptoRng, REPLY: super::AuxDataReply<Self>, T: AsRef<[u8]>>(
286 rng: &mut R,
287 reply_fn: &mut REPLY,
288 key: &[Self::KeyType],
289 msg: T,
290 ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)> {
291 let mut bytes_reply_fn = |bytes: &[u8]| -> Option<Vec<u8>> {
292 let client_exts = CircRequestExt::decode(bytes).ok()?;
293 let reply_exts = reply_fn.reply(&client_exts)?;
294 let mut out = vec![];
295 CircResponseExt::write_many_onto(&reply_exts, &mut out).ok()?;
296 Some(out)
297 };
298
299 let (res, reader) = server_handshake_ntor_v3(
300 rng,
301 &mut bytes_reply_fn,
302 msg.as_ref(),
303 key,
304 NTOR3_CIRC_VERIFICATION,
305 )?;
306 Ok((NtorV3KeyGenerator { reader }, res))
307 }
308}
309
310#[derive(Clone, Debug)]
315pub(crate) struct NtorV3PublicKey {
316 pub(crate) id: Ed25519Identity,
318 pub(crate) pk: curve25519::PublicKey,
320}
321
322pub(crate) struct NtorV3SecretKey {
324 pk: NtorV3PublicKey,
326 sk: curve25519::StaticSecret,
328}
329
330impl NtorV3SecretKey {
331 #[allow(unused)]
333 pub(crate) fn new(
334 sk: curve25519::StaticSecret,
335 pk: curve25519::PublicKey,
336 id: Ed25519Identity,
337 ) -> Self {
338 Self {
339 pk: NtorV3PublicKey { id, pk },
340 sk,
341 }
342 }
343
344 #[cfg(test)]
346 pub(crate) fn generate_for_test<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
347 let mut id = [0_u8; 32];
348 rng.fill_bytes(&mut id);
350
351 let sk = curve25519::StaticSecret::random_from_rng(rng);
352
353 let pk = NtorV3PublicKey {
354 pk: (&sk).into(),
355 id: id.into(),
356 };
357 Self { pk, sk }
358 }
359
360 fn matches(&self, id: Ed25519Identity, pk: curve25519::PublicKey) -> Choice {
364 id.as_bytes().ct_eq(self.pk.id.as_bytes()) & pk.as_bytes().ct_eq(self.pk.pk.as_bytes())
366 }
367}
368
369pub(crate) struct NtorV3HandshakeState {
374 relay_public: NtorV3PublicKey, my_sk: curve25519::StaticSecret, my_public: curve25519::PublicKey, shared_secret: curve25519::SharedSecret, msg_mac: MacVal, }
386
387pub(crate) struct NtorV3KeyGenerator {
389 reader: NtorV3XofReader,
391}
392
393impl KeyGenerator for NtorV3KeyGenerator {
394 fn expand(mut self, keylen: usize) -> Result<SecretBuf> {
395 use digest::XofReader;
396 let mut ret: SecretBuf = vec![0; keylen].into();
397 self.reader.read(ret.as_mut());
398 Ok(ret)
399 }
400}
401
402fn client_handshake_ntor_v3<R: RngCore + CryptoRng>(
408 rng: &mut R,
409 relay_public: &NtorV3PublicKey,
410 client_msg: &[u8],
411 verification: &[u8],
412) -> EncodeResult<(NtorV3HandshakeState, Vec<u8>)> {
413 let my_sk = curve25519::StaticSecret::random_from_rng(rng);
414 client_handshake_ntor_v3_no_keygen(relay_public, client_msg, verification, my_sk)
415}
416
417fn client_handshake_ntor_v3_no_keygen(
420 relay_public: &NtorV3PublicKey,
421 client_msg: &[u8],
422 verification: &[u8],
423 my_sk: curve25519::StaticSecret,
424) -> EncodeResult<(NtorV3HandshakeState, Vec<u8>)> {
425 let my_public = curve25519::PublicKey::from(&my_sk);
426 let bx = my_sk.diffie_hellman(&relay_public.pk);
427
428 let (enc_key, mut mac) = kdf_msgkdf(&bx, relay_public, &my_public, verification)?;
429
430 let encrypted_msg = encrypt(&enc_key, client_msg);
433 let msg_mac: DigestVal = {
434 use digest::Digest;
435 mac.write(&encrypted_msg)?;
436 mac.take().finalize().into()
437 };
438
439 let mut message = Vec::new();
440 message.write(&relay_public.id)?;
441 message.write(&relay_public.pk)?;
442 message.write(&my_public)?;
443 message.write(&encrypted_msg)?;
444 message.write(&msg_mac)?;
445
446 let state = NtorV3HandshakeState {
447 relay_public: relay_public.clone(),
448 my_sk,
449 my_public,
450 shared_secret: bx,
451 msg_mac,
452 };
453
454 Ok((state, message))
455}
456
457pub(crate) trait MsgReply {
462 fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>>;
467}
468
469impl<F> MsgReply for F
470where
471 F: FnMut(&[u8]) -> Option<Vec<u8>>,
472{
473 fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
474 self(msg)
475 }
476}
477
478fn server_handshake_ntor_v3<RNG: CryptoRng + RngCore, REPLY: MsgReply>(
489 rng: &mut RNG,
490 reply_fn: &mut REPLY,
491 message: &[u8],
492 keys: &[NtorV3SecretKey],
493 verification: &[u8],
494) -> RelayHandshakeResult<(Vec<u8>, NtorV3XofReader)> {
495 let secret_key_y = curve25519::StaticSecret::random_from_rng(rng);
496 server_handshake_ntor_v3_no_keygen(reply_fn, &secret_key_y, message, keys, verification)
497}
498
499fn server_handshake_ntor_v3_no_keygen<REPLY: MsgReply>(
501 reply_fn: &mut REPLY,
502 secret_key_y: &curve25519::StaticSecret,
503 message: &[u8],
504 keys: &[NtorV3SecretKey],
505 verification: &[u8],
506) -> RelayHandshakeResult<(Vec<u8>, NtorV3XofReader)> {
507 let mut r = Reader::from_slice(message);
509 let id: Ed25519Identity = r.extract()?;
510 let requested_pk: curve25519::PublicKey = r.extract()?;
511 let client_pk: curve25519::PublicKey = r.extract()?;
512 let client_msg = r.take_all_but(MAC_LEN)?;
513 let msg_mac: MacVal = r.extract()?;
514 r.should_be_exhausted()?;
515
516 let keypair = ct_lookup(keys, |key| key.matches(id, requested_pk));
518 let keypair = match keypair {
519 Some(k) => k,
520 None => return Err(RelayHandshakeError::MissingKey),
521 };
522
523 let xb = keypair.sk.diffie_hellman(&client_pk);
524 let (enc_key, mut mac) = kdf_msgkdf(&xb, &keypair.pk, &client_pk, verification)
525 .map_err(into_internal!("Can't apply ntor3 kdf."))?;
526 let computed_mac: DigestVal = {
528 use digest::Digest;
529 mac.write(client_msg)
530 .map_err(into_internal!("Can't compute MAC input."))?;
531 mac.take().finalize().into()
532 };
533 let y_pk: curve25519::PublicKey = (secret_key_y).into();
534 let xy = secret_key_y.diffie_hellman(&client_pk);
535
536 let mut okay = computed_mac.ct_eq(&msg_mac)
537 & ct::bool_to_choice(xy.was_contributory())
538 & ct::bool_to_choice(xb.was_contributory());
539
540 let plaintext_msg = decrypt(&enc_key, client_msg);
541
542 let reply = reply_fn.reply(&plaintext_msg);
544
545 okay &= ct::bool_to_choice(reply.is_some());
549 let reply = reply.unwrap_or_default();
550
551 let secret_input = {
555 let mut si = SecretBuf::new();
556 si.write(&xy)
557 .and_then(|_| si.write(&xb))
558 .and_then(|_| si.write(&keypair.pk.id))
559 .and_then(|_| si.write(&keypair.pk.pk))
560 .and_then(|_| si.write(&client_pk))
561 .and_then(|_| si.write(&y_pk))
562 .and_then(|_| si.write(PROTOID))
563 .and_then(|_| si.write(&Encap(verification)))
564 .map_err(into_internal!("can't derive ntor3 secret_input"))?;
565 si
566 };
567 let ntor_key_seed = h_key_seed(&secret_input);
568 let verify = h_verify(&secret_input);
569
570 let (enc_key, keystream) = {
571 use digest::{ExtendableOutput, XofReader};
572 let mut xof = DigestWriter(Shake256::default());
573 xof.write(&T_FINAL)
574 .and_then(|_| xof.write(&ntor_key_seed))
575 .map_err(into_internal!("can't generate ntor3 xof."))?;
576 let mut r = xof.take().finalize_xof();
577 let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
578 r.read(&mut enc_key[..]);
579 (enc_key, r)
580 };
581 let encrypted_reply = encrypt(&enc_key, &reply);
582 let auth: DigestVal = {
583 use digest::Digest;
584 let mut auth = DigestWriter(Sha3_256::default());
585 auth.write(&T_AUTH)
586 .and_then(|_| auth.write(&verify))
587 .and_then(|_| auth.write(&keypair.pk.id))
588 .and_then(|_| auth.write(&keypair.pk.pk))
589 .and_then(|_| auth.write(&y_pk))
590 .and_then(|_| auth.write(&client_pk))
591 .and_then(|_| auth.write(&msg_mac))
592 .and_then(|_| auth.write(&Encap(&encrypted_reply)))
593 .and_then(|_| auth.write(PROTOID))
594 .and_then(|_| auth.write(&b"Server"[..]))
595 .map_err(into_internal!("can't derive ntor3 authentication"))?;
596 auth.take().finalize().into()
597 };
598
599 let reply = {
600 let mut reply = Vec::new();
601 reply
602 .write(&y_pk)
603 .and_then(|_| reply.write(&auth))
604 .and_then(|_| reply.write(&encrypted_reply))
605 .map_err(into_internal!("can't encode ntor3 reply."))?;
606 reply
607 };
608
609 if okay.into() {
610 Ok((reply, NtorV3XofReader(keystream)))
611 } else {
612 Err(RelayHandshakeError::BadClientHandshake)
613 }
614}
615
616fn client_handshake_ntor_v3_part2(
624 state: &NtorV3HandshakeState,
625 relay_handshake: &[u8],
626 verification: &[u8],
627) -> Result<(Vec<u8>, NtorV3XofReader)> {
628 let mut reader = Reader::from_slice(relay_handshake);
629 let y_pk: curve25519::PublicKey = reader
630 .extract()
631 .map_err(|e| Error::from_bytes_err(e, "v3 ntor handshake"))?;
632 let auth: DigestVal = reader
633 .extract()
634 .map_err(|e| Error::from_bytes_err(e, "v3 ntor handshake"))?;
635 let encrypted_msg = reader.into_rest();
636
637 let yx = state.my_sk.diffie_hellman(&y_pk);
640 let secret_input = {
641 let mut si = SecretBuf::new();
642 si.write(&yx)
643 .and_then(|_| si.write(&state.shared_secret))
644 .and_then(|_| si.write(&state.relay_public.id))
645 .and_then(|_| si.write(&state.relay_public.pk))
646 .and_then(|_| si.write(&state.my_public))
647 .and_then(|_| si.write(&y_pk))
648 .and_then(|_| si.write(PROTOID))
649 .and_then(|_| si.write(&Encap(verification)))
650 .map_err(into_internal!("error encoding ntor3 secret_input"))?;
651 si
652 };
653 let ntor_key_seed = h_key_seed(&secret_input);
654 let verify = h_verify(&secret_input);
655
656 let computed_auth: DigestVal = {
657 use digest::Digest;
658 let mut auth = DigestWriter(Sha3_256::default());
659 auth.write(&T_AUTH)
660 .and_then(|_| auth.write(&verify))
661 .and_then(|_| auth.write(&state.relay_public.id))
662 .and_then(|_| auth.write(&state.relay_public.pk))
663 .and_then(|_| auth.write(&y_pk))
664 .and_then(|_| auth.write(&state.my_public))
665 .and_then(|_| auth.write(&state.msg_mac))
666 .and_then(|_| auth.write(&Encap(encrypted_msg)))
667 .and_then(|_| auth.write(PROTOID))
668 .and_then(|_| auth.write(&b"Server"[..]))
669 .map_err(into_internal!("error encoding ntor3 authentication input"))?;
670 auth.take().finalize().into()
671 };
672
673 let okay = computed_auth.ct_eq(&auth)
674 & ct::bool_to_choice(yx.was_contributory())
675 & ct::bool_to_choice(state.shared_secret.was_contributory());
676
677 let (enc_key, keystream) = {
678 use digest::{ExtendableOutput, XofReader};
679 let mut xof = DigestWriter(Shake256::default());
680 xof.write(&T_FINAL)
681 .and_then(|_| xof.write(&ntor_key_seed))
682 .map_err(into_internal!("error encoding ntor3 xof input"))?;
683 let mut r = xof.take().finalize_xof();
684 let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
685 r.read(&mut enc_key[..]);
686 (enc_key, r)
687 };
688 let server_reply = decrypt(&enc_key, encrypted_msg);
689
690 if okay.into() {
691 Ok((server_reply, NtorV3XofReader(keystream)))
692 } else {
693 Err(Error::BadCircHandshakeAuth)
694 }
695}
696
697#[cfg(test)]
698#[allow(non_snake_case)] #[allow(clippy::many_single_char_names)] mod test {
701 #![allow(clippy::bool_assert_comparison)]
703 #![allow(clippy::clone_on_copy)]
704 #![allow(clippy::dbg_macro)]
705 #![allow(clippy::mixed_attributes_style)]
706 #![allow(clippy::print_stderr)]
707 #![allow(clippy::print_stdout)]
708 #![allow(clippy::single_char_pattern)]
709 #![allow(clippy::unwrap_used)]
710 #![allow(clippy::unchecked_duration_subtraction)]
711 #![allow(clippy::useless_vec)]
712 #![allow(clippy::needless_pass_by_value)]
713 use crate::crypto::handshake::{ClientHandshake, ServerHandshake};
715
716 use super::*;
717 use hex_literal::hex;
718 use tor_basic_utils::test_rng::testing_rng;
719 use tor_cell::relaycell::extend::{CcRequest, CcResponse, CircResponseExt};
720
721 #[test]
722 fn test_ntor3_roundtrip() {
723 let mut rng = rand::rng();
724 let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
725
726 let verification = &b"shared secret"[..];
727 let client_message = &b"Hello. I am a client. Let's be friends!"[..];
728 let relay_message = &b"Greetings, client. I am a robot. Beep boop."[..];
729
730 let (c_state, c_handshake) =
731 client_handshake_ntor_v3(&mut rng, &relay_private.pk, client_message, verification)
732 .unwrap();
733
734 struct Rep(Vec<u8>, Vec<u8>);
735 impl MsgReply for Rep {
736 fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
737 self.0 = msg.to_vec();
738 Some(self.1.clone())
739 }
740 }
741 let mut rep = Rep(Vec::new(), relay_message.to_vec());
742
743 let (s_handshake, mut s_keygen) = server_handshake_ntor_v3(
744 &mut rng,
745 &mut rep,
746 &c_handshake,
747 &[relay_private],
748 verification,
749 )
750 .unwrap();
751
752 let (s_msg, mut c_keygen) =
753 client_handshake_ntor_v3_part2(&c_state, &s_handshake, verification).unwrap();
754
755 assert_eq!(rep.0[..], client_message[..]);
756 assert_eq!(s_msg[..], relay_message[..]);
757 use digest::XofReader;
758 let mut s_keys = [0_u8; 100];
759 let mut c_keys = [0_u8; 1000];
760 s_keygen.read(&mut s_keys);
761 c_keygen.read(&mut c_keys);
762 assert_eq!(s_keys[..], c_keys[..100]);
763 }
764
765 #[test]
767 fn test_ntor3_roundtrip_highlevel() {
768 let mut rng = rand::rng();
769 let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
770
771 let (c_state, c_handshake) =
772 NtorV3Client::client1(&mut rng, &relay_private.pk, &[]).unwrap();
773
774 let mut rep = |_: &[CircRequestExt]| Some(vec![]);
775
776 let (s_keygen, s_handshake) =
777 NtorV3Server::server(&mut rng, &mut rep, &[relay_private], &c_handshake).unwrap();
778
779 let (extensions, keygen) = NtorV3Client::client2(c_state, s_handshake).unwrap();
780
781 assert!(extensions.is_empty());
782 let c_keys = keygen.expand(1000).unwrap();
783 let s_keys = s_keygen.expand(100).unwrap();
784 assert_eq!(s_keys[..], c_keys[..100]);
785 }
786
787 #[test]
789 fn test_ntor3_roundtrip_highlevel_cc() {
790 let mut rng = rand::rng();
791 let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
792
793 let client_exts = vec![CircRequestExt::CcRequest(CcRequest::default())];
794 let reply_exts = vec![CircResponseExt::CcResponse(CcResponse::new(42))];
795
796 let (c_state, c_handshake) = NtorV3Client::client1(
797 &mut rng,
798 &relay_private.pk,
799 &[CircRequestExt::CcRequest(CcRequest::default())],
800 )
801 .unwrap();
802
803 let mut rep = |msg: &[CircRequestExt]| -> Option<Vec<CircResponseExt>> {
804 assert_eq!(msg, client_exts);
805 Some(reply_exts.clone())
806 };
807
808 let (s_keygen, s_handshake) =
809 NtorV3Server::server(&mut rng, &mut rep, &[relay_private], &c_handshake).unwrap();
810
811 let (extensions, keygen) = NtorV3Client::client2(c_state, s_handshake).unwrap();
812
813 assert_eq!(extensions, reply_exts);
814 let c_keys = keygen.expand(1000).unwrap();
815 let s_keys = s_keygen.expand(100).unwrap();
816 assert_eq!(s_keys[..], c_keys[..100]);
817 }
818
819 #[test]
820 fn test_ntor3_testvec() {
821 let b = hex!("4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
822 let id = hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
823 let x = hex!("b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49");
824 let y = hex!("4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053");
825 let b: curve25519::StaticSecret = b.into();
826 let B: curve25519::PublicKey = (&b).into();
827 let id: Ed25519Identity = id.into();
828 let x: curve25519::StaticSecret = x.into();
829 let y: curve25519::StaticSecret = y.into();
831
832 let client_message = hex!("68656c6c6f20776f726c64");
833 let verification = hex!("78797a7a79");
834 let server_message = hex!("486f6c61204d756e646f");
835
836 let relay_public = NtorV3PublicKey { pk: B, id };
837 let relay_private = NtorV3SecretKey {
838 sk: b,
839 pk: relay_public.clone(),
840 };
841
842 let (state, client_handshake) =
843 client_handshake_ntor_v3_no_keygen(&relay_public, &client_message, &verification, x)
844 .unwrap();
845
846 assert_eq!(client_handshake[..], hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea65db8be9c72b68cd461942088502f67")[..]);
847
848 struct Replier(Vec<u8>, Vec<u8>, bool);
849 impl MsgReply for Replier {
850 fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
851 assert_eq!(msg, &self.0);
852 self.2 = true;
853 Some(self.1.clone())
854 }
855 }
856 let mut rep = Replier(client_message.to_vec(), server_message.to_vec(), false);
857
858 let (server_handshake, mut server_keygen) = server_handshake_ntor_v3_no_keygen(
859 &mut rep,
860 &y,
861 &client_handshake,
862 &[relay_private],
863 &verification,
864 )
865 .unwrap();
866 assert!(rep.2);
867
868 assert_eq!(server_handshake[..], hex!("4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461ab130c5b18ab0a91276651202c3e1e87c0d32054c")[..]);
869
870 let (server_msg_received, mut client_keygen) =
871 client_handshake_ntor_v3_part2(&state, &server_handshake, &verification).unwrap();
872 assert_eq!(&server_msg_received, &server_message);
873
874 let (c_keys, s_keys) = {
875 use digest::XofReader;
876 let mut c = [0_u8; 256];
877 let mut s = [0_u8; 256];
878 client_keygen.read(&mut c);
879 server_keygen.read(&mut s);
880 (c, s)
881 };
882 assert_eq!(c_keys, s_keys);
883 assert_eq!(c_keys[..], hex!("9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00fa8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b09749b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fcff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a")[..]);
884 }
885}