1 //! Implements the ntor v3 key exchange, as described in proposal 332.
2 //!
3 //! The main difference between the ntor v3r handshake and the
4 //! original ntor handshake is that this this one allows each party to
5 //! encrypt data (without forward secrecy) after it sends the first
6 //! message.
7 
8 // TODO:
9 //    Wrap this in an appropriate API, expanding the API as needed.
10 //    Remove the "allow" item for dead_code.
11 //    Make terminology and variable names consistent with spec.
12 
13 // This module is still unused: so allow some dead code for now.
14 #![allow(dead_code)]
15 
16 use crate::util::ct;
17 use crate::{Error, Result};
18 use tor_bytes::{Reader, Writeable, Writer};
19 use tor_llcrypto::d::{Sha3_256, Shake256};
20 use tor_llcrypto::pk::{curve25519, ed25519::Ed25519Identity};
21 use tor_llcrypto::util::rand_compat::RngCompatExt;
22 
23 use cipher::{NewCipher, StreamCipher};
24 
25 use generic_array::GenericArray;
26 use rand_core::{CryptoRng, RngCore};
27 use subtle::{Choice, ConstantTimeEq};
28 use tor_llcrypto::cipher::aes::Aes256Ctr;
29 use zeroize::Zeroizing;
30 
31 /// The size of an encryption key in bytes.
32 const ENC_KEY_LEN: usize = 32;
33 /// The size of a MAC key in bytes.
34 const MAC_KEY_LEN: usize = 32;
35 /// The size of a curve25519 public key in bytes.
36 const PUB_KEY_LEN: usize = 32;
37 /// The size of a digest output in bytes.
38 const DIGEST_LEN: usize = 32;
39 /// The length of a MAC output in bytes.
40 const MAC_LEN: usize = 32;
41 /// The length of a node identity in bytes.
42 const ID_LEN: usize = 32;
43 
44 /// The output of the digest, as an array.
45 type DigestVal = [u8; DIGEST_LEN];
46 /// The output of the MAC.
47 type MacVal = [u8; MAC_LEN];
48 /// A key for symmetric encryption or decryption.
49 type EncKey = [u8; ENC_KEY_LEN];
50 /// A key for message authentication codes.
51 type MacKey = [u8; MAC_KEY_LEN];
52 
53 /// An encapsulated value for passing as input to a MAC, digest, or
54 /// KDF algorithm.
55 ///
56 /// This corresponds to the ENCAP() function in proposal 332.
57 struct Encap<'a>(&'a [u8]);
58 
59 impl<'a> Writeable for Encap<'a> {
write_onto<B: Writer + ?Sized>(&self, b: &mut B)60     fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) {
61         b.write_u64(self.0.len() as u64);
62         b.write(self.0);
63     }
64 }
65 
66 impl<'a> Encap<'a> {
67     /// Return the length of the underlying data in bytes.
len(&self) -> usize68     fn len(&self) -> usize {
69         self.0.len()
70     }
71     /// Return the underlying data
data(&self) -> &'a [u8]72     fn data(&self) -> &'a [u8] {
73         self.0
74     }
75 }
76 
77 /// Helper to define a set of tweak values as instances of `Encap`.
78 macro_rules! define_tweaks {
79     {
80         $(#[$pid_meta:meta])*
81         PROTOID = $protoid:expr;
82         $( $(#[$meta:meta])* $name:ident <= $suffix:expr ; )*
83     } => {
84         $(#[$pid_meta])*
85         const PROTOID: &'static [u8] = $protoid.as_bytes();
86         $(
87             $(#[$meta])*
88             const $name : Encap<'static> =
89                 Encap(concat!($protoid, ":", $suffix).as_bytes());
90         )*
91     }
92 }
93 
94 define_tweaks! {
95     /// Protocol ID: concatenated with other things in the protocol to
96     /// prevent hash confusion.
97     PROTOID =  "ntor3-curve25519-sha3_256-1";
98 
99     /// Message MAC tweak: used to compute the MAC of an encrypted client
100     /// message.
101     T_MSGMAC <= "msg_mac";
102     /// Message KDF tweak: used when deriving keys for encrypting and MACing
103     /// client message.
104     T_MSGKDF <= "kdf_phase1";
105     /// Key seeding tweak: used to derive final KDF input from secret_input.
106     T_KEY_SEED <= "key_seed";
107     /// Verifying tweak: used to derive 'verify' value from secret_input.
108     T_VERIFY <= "verify";
109     /// Final KDF tweak: used to derive keys for encrypting relay message
110     /// and for the actual tor circuit.
111     T_FINAL <= "kdf_final";
112     /// Authentication tweak: used to derive the final authentication
113     /// value for the handshake.
114     T_AUTH <= "auth_final";
115 }
116 
117 /// Compute a tweaked hash.
hash(t: &Encap<'_>, data: &[u8]) -> DigestVal118 fn hash(t: &Encap<'_>, data: &[u8]) -> DigestVal {
119     use digest::Digest;
120     let mut d = Sha3_256::new();
121     d.update((t.len() as u64).to_be_bytes());
122     d.update(t.data());
123     d.update(data);
124     d.finalize().into()
125 }
126 
127 /// Perform a symmetric encryption operation and return the encrypted data.
128 ///
129 /// (This isn't safe to do more than once with the same key, but we never
130 /// do that in this protocol.)
encrypt(key: &EncKey, m: &[u8]) -> Vec<u8>131 fn encrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
132     let mut d = m.to_vec();
133     let zero_iv = GenericArray::default();
134     let mut cipher = Aes256Ctr::new(key.into(), &zero_iv);
135     cipher.apply_keystream(&mut d);
136     d
137 }
138 /// Perform a symmetric decryption operation and return the encrypted data.
decrypt(key: &EncKey, m: &[u8]) -> Vec<u8>139 fn decrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
140     encrypt(key, m)
141 }
142 
143 /// Wrapper around a Digest or ExtendedOutput object that lets us use it
144 /// as a tor_bytes::Writer.
145 struct DigestWriter<U>(U);
146 impl<U: digest::Update> tor_bytes::Writer for DigestWriter<U> {
write_all(&mut self, bytes: &[u8])147     fn write_all(&mut self, bytes: &[u8]) {
148         self.0.update(bytes);
149     }
150 }
151 impl<U> DigestWriter<U> {
152     /// Consume this wrapper and return the underlying object.
take(self) -> U153     fn take(self) -> U {
154         self.0
155     }
156 }
157 
158 /// Hash tweaked with T_KEY_SEED
h_key_seed(d: &[u8]) -> DigestVal159 fn h_key_seed(d: &[u8]) -> DigestVal {
160     hash(&T_KEY_SEED, d)
161 }
162 /// Hash tweaked with T_VERIFY
h_verify(d: &[u8]) -> DigestVal163 fn h_verify(d: &[u8]) -> DigestVal {
164     hash(&T_VERIFY, d)
165 }
166 
167 /// Helper: compute the encryption key and mac_key for the client's
168 /// encrypted message.
169 ///
170 /// Takes as inputs `xb` (the shared secret derived from
171 /// diffie-hellman as Bx or Xb), the relay's public key information,
172 /// the client's public key (B), and the shared verification string.
kdf_msgkdf( xb: &curve25519::SharedSecret, relay_public: &NtorV3PublicKey, client_public: &curve25519::PublicKey, verification: &[u8], ) -> (Zeroizing<EncKey>, DigestWriter<Sha3_256>)173 fn kdf_msgkdf(
174     xb: &curve25519::SharedSecret,
175     relay_public: &NtorV3PublicKey,
176     client_public: &curve25519::PublicKey,
177     verification: &[u8],
178 ) -> (Zeroizing<EncKey>, DigestWriter<Sha3_256>) {
179     // secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER)
180     // phase1_keys = KDF_msgkdf(secret_input_phase1)
181     // (ENC_K1, MAC_K1) = PARTITION(phase1_keys, ENC_KEY_LEN, MAC_KEY_LEN
182     use digest::{ExtendableOutput, XofReader};
183     let mut msg_kdf = DigestWriter(Shake256::default());
184     msg_kdf.write(&T_MSGKDF);
185     msg_kdf.write(xb);
186     msg_kdf.write(&relay_public.id);
187     msg_kdf.write(client_public);
188     msg_kdf.write(&relay_public.pk);
189     msg_kdf.write(PROTOID);
190     msg_kdf.write(&Encap(verification));
191     let mut r = msg_kdf.take().finalize_xof();
192     let mut enc_key = Zeroizing::new([0; ENC_KEY_LEN]);
193     let mut mac_key = Zeroizing::new([0; MAC_KEY_LEN]);
194 
195     r.read(&mut enc_key[..]);
196     r.read(&mut mac_key[..]);
197     let mut mac = DigestWriter(Sha3_256::default());
198     {
199         mac.write(&T_MSGMAC);
200         mac.write(&Encap(&mac_key[..]));
201         mac.write(&relay_public.id);
202         mac.write(&relay_public.pk);
203         mac.write(client_public);
204     }
205 
206     (enc_key, mac)
207 }
208 
209 /*
210 /// TODO
211 pub(crate) struct NtorV3Client {
212     message: Vec<u8>,
213 }
214 */
215 
216 /// Key information about a relay used for the ntor v3 handshake.
217 ///
218 /// Contains a single curve25519 ntor onion key, and the relay's ed25519
219 /// identity.
220 #[derive(Clone, Debug)]
221 pub(crate) struct NtorV3PublicKey {
222     /// The relay's identity.
223     id: Ed25519Identity,
224     /// The relay's onion key.
225     pk: curve25519::PublicKey,
226 }
227 
228 /// Secret key information used by a relay for the ntor v3 handshake.
229 pub(crate) struct NtorV3SecretKey {
230     /// The relay's public key information
231     pk: NtorV3PublicKey,
232     /// The secret onion key.
233     sk: curve25519::StaticSecret,
234 }
235 
236 impl NtorV3SecretKey {
237     /// Checks whether `id` and `pk` match this secret key.
238     ///
239     /// Used to perform a constant-time secret key lookup.
matches(&self, id: Ed25519Identity, pk: curve25519::PublicKey) -> Choice240     fn matches(&self, id: Ed25519Identity, pk: curve25519::PublicKey) -> Choice {
241         // TODO: use similar pattern in ntor_v1!
242         id.as_bytes().ct_eq(self.pk.id.as_bytes()) & pk.as_bytes().ct_eq(self.pk.pk.as_bytes())
243     }
244 }
245 
246 /// Client state for the ntor v3 handshake.
247 ///
248 /// The client needs to hold this state between when it sends its part
249 /// of the handshake and when it receives the relay's reply.
250 pub(crate) struct NtorV3HandshakeState {
251     /// The public key of the relay we're communicating with.
252     relay_public: NtorV3PublicKey, // B, ID.
253     /// Our ephemeral secret key for this handshake.
254     my_sk: curve25519::StaticSecret, // x
255     /// Our ephemeral public key for this handshake.
256     my_public: curve25519::PublicKey, // X
257 
258     /// The shared secret generated as Bx or Xb.
259     shared_secret: curve25519::SharedSecret, // Bx
260     /// The MAC of our original encrypted message.
261     msg_mac: MacVal, // msg_mac
262 }
263 
264 /*
265 ///
266 pub(crate) struct NtorV3KeyGenerator {
267     seed: SecretBytes,
268 }
269 */
270 
271 /// Client-side Ntor version 3 handshake, part one.
272 ///
273 /// Given a secure `rng`, a relay's public key, a secret message to send,
274 /// and a shared verification string, generate a new handshake state
275 /// and a message to send to the relay.
client_handshake_ntor_v3<R: RngCore + CryptoRng>( rng: &mut R, relay_public: &NtorV3PublicKey, client_msg: &[u8], verification: &[u8], ) -> (NtorV3HandshakeState, Vec<u8>)276 fn client_handshake_ntor_v3<R: RngCore + CryptoRng>(
277     rng: &mut R,
278     relay_public: &NtorV3PublicKey,
279     client_msg: &[u8],
280     verification: &[u8],
281 ) -> (NtorV3HandshakeState, Vec<u8>) {
282     let my_sk = curve25519::StaticSecret::new(rng.rng_compat());
283     client_handshake_ntor_v3_no_keygen(relay_public, client_msg, verification, my_sk)
284 }
285 
286 /// As `client_handshake_ntor_v3`, but don't generate an ephemeral DH
287 /// key: instead take that key an arguments `my_sk`.
client_handshake_ntor_v3_no_keygen( relay_public: &NtorV3PublicKey, client_msg: &[u8], verification: &[u8], my_sk: curve25519::StaticSecret, ) -> (NtorV3HandshakeState, Vec<u8>)288 fn client_handshake_ntor_v3_no_keygen(
289     relay_public: &NtorV3PublicKey,
290     client_msg: &[u8],
291     verification: &[u8],
292     my_sk: curve25519::StaticSecret,
293 ) -> (NtorV3HandshakeState, Vec<u8>) {
294     let my_public = curve25519::PublicKey::from(&my_sk);
295     let bx = my_sk.diffie_hellman(&relay_public.pk);
296 
297     let (enc_key, mut mac) = kdf_msgkdf(&bx, relay_public, &my_public, verification);
298 
299     //encrypted_msg = ENC(ENC_K1, CM)
300     // msg_mac = MAC_msgmac(MAC_K1, ID | B | X | encrypted_msg)
301     let encrypted_msg = encrypt(&enc_key, client_msg);
302     let msg_mac: DigestVal = {
303         use digest::Digest;
304         mac.write(&encrypted_msg);
305         mac.take().finalize().into()
306     };
307 
308     let mut message = Vec::new();
309     message.write(&relay_public.id);
310     message.write(&relay_public.pk);
311     message.write(&my_public);
312     message.write(&encrypted_msg);
313     message.write(&msg_mac);
314 
315     let state = NtorV3HandshakeState {
316         relay_public: relay_public.clone(),
317         my_sk,
318         my_public,
319         shared_secret: bx,
320         msg_mac,
321     };
322 
323     (state, message)
324 }
325 
326 /// Trait for an object that handle and incoming client message and
327 /// return a server's reply.
328 ///
329 // XXXX I wanted to use a closure here, but the lifetimes didn't work.
330 pub(crate) trait MsgReply {
331     /// Given a message received from a client, parse it and decide
332     /// how (and whether) to reply.
333     ///
334     /// Return None if the handshake should fail.
reply(&mut self, msg: &[u8]) -> Option<Vec<u8>>335     fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>>;
336 }
337 
338 /// Complete an ntor v3 handshake as a server.
339 ///
340 /// Use the provided `rng` to generate keys; use the provided
341 /// `reply_fn` to handle incoming client secret message and decide how
342 /// to reply.  The client's handshake is in `message`.  Our private
343 /// key(s) are in `keys`.  The `verification` string must match the
344 /// string provided by the client.
345 ///
346 /// On success, return the server handshake message to send, and an XofReader
347 /// to use in generating circuit keys.
server_handshake_ntor_v3<RNG: CryptoRng + RngCore, REPLY: MsgReply>( rng: &mut RNG, reply_fn: &mut REPLY, message: &[u8], keys: &[NtorV3SecretKey], verification: &[u8], ) -> Result<(Vec<u8>, impl digest::XofReader)>348 fn server_handshake_ntor_v3<RNG: CryptoRng + RngCore, REPLY: MsgReply>(
349     rng: &mut RNG,
350     reply_fn: &mut REPLY,
351     message: &[u8],
352     keys: &[NtorV3SecretKey],
353     verification: &[u8],
354 ) -> Result<(Vec<u8>, impl digest::XofReader)> {
355     let secret_key_y = curve25519::StaticSecret::new(rng.rng_compat());
356     server_handshake_ntor_v3_no_keygen(reply_fn, &secret_key_y, message, keys, verification)
357 }
358 
359 /// As `server_handshake_ntor_v3`, but take a secret key instead of an RNG.
server_handshake_ntor_v3_no_keygen<REPLY: MsgReply>( reply_fn: &mut REPLY, secret_key_y: &curve25519::StaticSecret, message: &[u8], keys: &[NtorV3SecretKey], verification: &[u8], ) -> Result<(Vec<u8>, impl digest::XofReader)>360 fn server_handshake_ntor_v3_no_keygen<REPLY: MsgReply>(
361     reply_fn: &mut REPLY,
362     secret_key_y: &curve25519::StaticSecret,
363     message: &[u8],
364     keys: &[NtorV3SecretKey],
365     verification: &[u8],
366 ) -> Result<(Vec<u8>, impl digest::XofReader)> {
367     // Decode the message.
368     let mut r = Reader::from_slice(message);
369     let id: Ed25519Identity = r.extract()?;
370     let requested_pk: curve25519::PublicKey = r.extract()?;
371     let client_pk: curve25519::PublicKey = r.extract()?;
372     let client_msg = if let Some(msg_len) = r.remaining().checked_sub(MAC_LEN) {
373         r.take(msg_len)?
374     } else {
375         return Err(tor_bytes::Error::Truncated.into());
376     };
377     let msg_mac: MacVal = r.extract()?;
378     r.should_be_exhausted()?;
379 
380     // See if we recognize the provided (id,requested_pk) pair.
381     let keypair = ct::lookup(keys, |key| key.matches(id, requested_pk));
382     let keypair = match keypair {
383         Some(k) => k,
384         None => return Err(Error::MissingKey),
385     };
386 
387     let xb = keypair.sk.diffie_hellman(&client_pk);
388     let (enc_key, mut mac) = kdf_msgkdf(&xb, &keypair.pk, &client_pk, verification);
389     // Verify the message we received.
390     let computed_mac: DigestVal = {
391         use digest::Digest;
392         mac.write(client_msg);
393         mac.take().finalize().into()
394     };
395     let y_pk: curve25519::PublicKey = (secret_key_y).into();
396     let xy = secret_key_y.diffie_hellman(&client_pk);
397 
398     let mut okay = computed_mac.ct_eq(&msg_mac)
399         & ct::bool_to_choice(xy.was_contributory())
400         & ct::bool_to_choice(xb.was_contributory());
401 
402     let plaintext_msg = decrypt(&enc_key, client_msg);
403 
404     // Handle the message and decide how to reply.
405     let reply = reply_fn.reply(&plaintext_msg);
406 
407     // It's not exactly constant time to use is_some() and
408     // unwrap_or_else() here, but that should be somewhat
409     // hidden by the rest of the computation.
410     okay &= ct::bool_to_choice(reply.is_some());
411     let reply = reply.unwrap_or_else(Vec::new);
412 
413     // If we reach this point, we are actually replying, or pretending
414     // that we're going to reply.
415 
416     let secret_input = {
417         let mut si = Zeroizing::new(Vec::new());
418         si.write(&xy);
419         si.write(&xb);
420         si.write(&keypair.pk.id);
421         si.write(&keypair.pk.pk);
422         si.write(&client_pk);
423         si.write(&y_pk);
424         si.write(PROTOID);
425         si.write(&Encap(verification));
426         si
427     };
428     let ntor_key_seed = h_key_seed(&secret_input);
429     let verify = h_verify(&secret_input);
430 
431     let (enc_key, keystream) = {
432         use digest::{ExtendableOutput, XofReader};
433         let mut xof = DigestWriter(Shake256::default());
434         xof.write(&T_FINAL);
435         xof.write(&ntor_key_seed);
436         let mut r = xof.take().finalize_xof();
437         let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
438         r.read(&mut enc_key[..]);
439         (enc_key, r)
440     };
441     let encrypted_reply = encrypt(&enc_key, &reply);
442     let auth: DigestVal = {
443         use digest::Digest;
444         let mut auth = DigestWriter(Sha3_256::default());
445         auth.write(&T_AUTH);
446         auth.write(&verify);
447         auth.write(&keypair.pk.id);
448         auth.write(&keypair.pk.pk);
449         auth.write(&y_pk);
450         auth.write(&client_pk);
451         auth.write(&msg_mac);
452         auth.write(&Encap(&encrypted_reply));
453         auth.write(PROTOID);
454         auth.write(&b"Server"[..]);
455         auth.take().finalize().into()
456     };
457 
458     let reply = {
459         let mut reply = Vec::new();
460         reply.write(&y_pk);
461         reply.write(&auth);
462         reply.write(&encrypted_reply);
463         reply
464     };
465 
466     if okay.into() {
467         Ok((reply, keystream))
468     } else {
469         Err(Error::BadHandshake)
470     }
471 }
472 
473 /// Finalize the handshake on the client side.
474 ///
475 /// Called after we've received a message from the relay: try to
476 /// complete the handshake and verify its correctness.
477 ///
478 /// On success, return the server's reply to our original encrypted message,
479 /// and an `XofReader` to use in generating circuit keys.
client_handshake_ntor_v3_part2( state: &NtorV3HandshakeState, relay_handshake: &[u8], verification: &[u8], ) -> Result<(Vec<u8>, impl digest::XofReader)>480 fn client_handshake_ntor_v3_part2(
481     state: &NtorV3HandshakeState,
482     relay_handshake: &[u8],
483     verification: &[u8],
484 ) -> Result<(Vec<u8>, impl digest::XofReader)> {
485     let mut reader = Reader::from_slice(relay_handshake);
486     let y_pk: curve25519::PublicKey = reader.extract()?;
487     let auth: DigestVal = reader.extract()?;
488     let encrypted_msg = reader.into_rest();
489 
490     let yx = state.my_sk.diffie_hellman(&y_pk);
491     let secret_input = {
492         let mut si = Zeroizing::new(Vec::new());
493         si.write(&yx);
494         si.write(&state.shared_secret);
495         si.write(&state.relay_public.id);
496         si.write(&state.relay_public.pk);
497         si.write(&state.my_public);
498         si.write(&y_pk);
499         si.write(PROTOID);
500         si.write(&Encap(verification));
501         si
502     };
503     let ntor_key_seed = h_key_seed(&secret_input);
504     let verify = h_verify(&secret_input);
505 
506     let computed_auth: DigestVal = {
507         use digest::Digest;
508         let mut auth = DigestWriter(Sha3_256::default());
509         auth.write(&T_AUTH);
510         auth.write(&verify);
511         auth.write(&state.relay_public.id);
512         auth.write(&state.relay_public.pk);
513         auth.write(&y_pk);
514         auth.write(&state.my_public);
515         auth.write(&state.msg_mac);
516         auth.write(&Encap(encrypted_msg));
517         auth.write(PROTOID);
518         auth.write(&b"Server"[..]);
519         auth.take().finalize().into()
520     };
521 
522     let okay = computed_auth.ct_eq(&auth)
523         & ct::bool_to_choice(yx.was_contributory())
524         & ct::bool_to_choice(state.shared_secret.was_contributory());
525 
526     let (enc_key, keystream) = {
527         use digest::{ExtendableOutput, XofReader};
528         let mut xof = DigestWriter(Shake256::default());
529         xof.write(&T_FINAL);
530         xof.write(&ntor_key_seed);
531         let mut r = xof.take().finalize_xof();
532         let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
533         r.read(&mut enc_key[..]);
534         (enc_key, r)
535     };
536     let server_reply = decrypt(&enc_key, encrypted_msg);
537 
538     if okay.into() {
539         Ok((server_reply, keystream))
540     } else {
541         Err(Error::BadHandshake)
542     }
543 }
544 
545 /*
546 impl super::ClientHandshake for NtorV3Client {
547     type KeyType = NtorPublicKey;
548     type StateType = NtorV3HandshakeState;
549     type KeyGen = NtorV3KeyGenerator;
550 
551 
552 }
553 */
554 
555 #[cfg(test)]
556 #[allow(non_snake_case)] // to enable variable names matching the spec.
557 #[allow(clippy::many_single_char_names)] // ibid
558 #[allow(clippy::unwrap_used)]
559 mod test {
560     use super::*;
561     use hex_literal::hex;
562 
563     #[test]
test_ntor3_roundtrip()564     fn test_ntor3_roundtrip() {
565         let b = curve25519::StaticSecret::new(rand::thread_rng().rng_compat());
566         let mut rng = rand::thread_rng();
567         let id = b"not identifier---but correct len";
568 
569         let B: curve25519::PublicKey = (&b).into();
570         let relay_public = NtorV3PublicKey {
571             pk: B,
572             id: (*id).into(),
573         };
574         let relay_private = NtorV3SecretKey {
575             pk: relay_public.clone(),
576             sk: b,
577         };
578 
579         let verification = &b"shared secret"[..];
580         let client_message = &b"Hello. I am a client. Let's be friends!"[..];
581         let relay_message = &b"Greetings, client. I am a robot. Beep boop."[..];
582 
583         let (c_state, c_handshake) =
584             client_handshake_ntor_v3(&mut rng, &relay_public, client_message, verification);
585 
586         struct Rep(Vec<u8>, Vec<u8>);
587         impl MsgReply for Rep {
588             fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
589                 self.0 = msg.to_vec();
590                 Some(self.1.clone())
591             }
592         }
593         let mut rep = Rep(Vec::new(), relay_message.to_vec());
594 
595         let (s_handshake, mut s_keygen) = server_handshake_ntor_v3(
596             &mut rng,
597             &mut rep,
598             &c_handshake,
599             &[relay_private],
600             verification,
601         )
602         .unwrap();
603 
604         let (s_msg, mut c_keygen) =
605             client_handshake_ntor_v3_part2(&c_state, &s_handshake, verification).unwrap();
606 
607         assert_eq!(rep.0[..], client_message[..]);
608         assert_eq!(s_msg[..], relay_message[..]);
609         use digest::XofReader;
610         let mut s_keys = [0_u8; 100];
611         let mut c_keys = [0_u8; 1000];
612         s_keygen.read(&mut s_keys);
613         c_keygen.read(&mut c_keys);
614         assert_eq!(s_keys[..], c_keys[..100]);
615     }
616 
617     #[test]
test_ntor3_testvec()618     fn test_ntor3_testvec() {
619         let b = hex!("4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
620         let id = hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
621         let x = hex!("b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49");
622         let y = hex!("4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053");
623         let b: curve25519::StaticSecret = b.into();
624         let B: curve25519::PublicKey = (&b).into();
625         let id: Ed25519Identity = id.into();
626         let x: curve25519::StaticSecret = x.into();
627         //let X = (&x).into();
628         let y: curve25519::StaticSecret = y.into();
629 
630         let client_message = hex!("68656c6c6f20776f726c64");
631         let verification = hex!("78797a7a79");
632         let server_message = hex!("486f6c61204d756e646f");
633 
634         let relay_public = NtorV3PublicKey { pk: B, id };
635         let relay_private = NtorV3SecretKey {
636             sk: b,
637             pk: relay_public.clone(),
638         };
639 
640         let (state, client_handshake) =
641             client_handshake_ntor_v3_no_keygen(&relay_public, &client_message, &verification, x);
642 
643         assert_eq!(client_handshake[..], hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea65db8be9c72b68cd461942088502f67")[..]);
644 
645         struct Replier(Vec<u8>, Vec<u8>, bool);
646         impl MsgReply for Replier {
647             fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
648                 assert_eq!(msg, &self.0);
649                 self.2 = true;
650                 Some(self.1.clone())
651             }
652         }
653         let mut rep = Replier(client_message.to_vec(), server_message.to_vec(), false);
654 
655         let (server_handshake, mut server_keygen) = server_handshake_ntor_v3_no_keygen(
656             &mut rep,
657             &y,
658             &client_handshake,
659             &[relay_private],
660             &verification,
661         )
662         .unwrap();
663         assert!(rep.2);
664 
665         assert_eq!(server_handshake[..], hex!("4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461ab130c5b18ab0a91276651202c3e1e87c0d32054c")[..]);
666 
667         let (server_msg_received, mut client_keygen) =
668             client_handshake_ntor_v3_part2(&state, &server_handshake, &verification).unwrap();
669         assert_eq!(&server_msg_received, &server_message);
670 
671         let (c_keys, s_keys) = {
672             use digest::XofReader;
673             let mut c = [0_u8; 256];
674             let mut s = [0_u8; 256];
675             client_keygen.read(&mut c);
676             server_keygen.read(&mut s);
677             (c, s)
678         };
679         assert_eq!(c_keys, s_keys);
680         assert_eq!(c_keys[..], hex!("9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00fa8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b09749b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fcff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a")[..]);
681     }
682 }
683