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 super::{RelayHandshakeError, RelayHandshakeResult};
17
use crate::util::ct;
18
use crate::{Error, Result};
19
use tor_bytes::{Reader, Writeable, Writer};
20
use tor_llcrypto::d::{Sha3_256, Shake256};
21
use tor_llcrypto::pk::{curve25519, ed25519::Ed25519Identity};
22
use tor_llcrypto::util::rand_compat::RngCompatExt;
23

            
24
use cipher::{NewCipher, StreamCipher};
25

            
26
use generic_array::GenericArray;
27
use rand_core::{CryptoRng, RngCore};
28
use subtle::{Choice, ConstantTimeEq};
29
use tor_llcrypto::cipher::aes::Aes256Ctr;
30
use zeroize::Zeroizing;
31

            
32
/// The size of an encryption key in bytes.
33
const ENC_KEY_LEN: usize = 32;
34
/// The size of a MAC key in bytes.
35
const MAC_KEY_LEN: usize = 32;
36
/// The size of a curve25519 public key in bytes.
37
const PUB_KEY_LEN: usize = 32;
38
/// The size of a digest output in bytes.
39
const DIGEST_LEN: usize = 32;
40
/// The length of a MAC output in bytes.
41
const MAC_LEN: usize = 32;
42
/// The length of a node identity in bytes.
43
const ID_LEN: usize = 32;
44

            
45
/// The output of the digest, as an array.
46
type DigestVal = [u8; DIGEST_LEN];
47
/// The output of the MAC.
48
type MacVal = [u8; MAC_LEN];
49
/// A key for symmetric encryption or decryption.
50
type EncKey = [u8; ENC_KEY_LEN];
51
/// A key for message authentication codes.
52
type MacKey = [u8; MAC_KEY_LEN];
53

            
54
/// An encapsulated value for passing as input to a MAC, digest, or
55
/// KDF algorithm.
56
///
57
/// This corresponds to the ENCAP() function in proposal 332.
58
struct Encap<'a>(&'a [u8]);
59

            
60
impl<'a> Writeable for Encap<'a> {
61
32
    fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) {
62
32
        b.write_u64(self.0.len() as u64);
63
32
        b.write(self.0);
64
32
    }
65
}
66

            
67
impl<'a> Encap<'a> {
68
    /// Return the length of the underlying data in bytes.
69
8
    fn len(&self) -> usize {
70
8
        self.0.len()
71
8
    }
72
    /// Return the underlying data
73
8
    fn data(&self) -> &'a [u8] {
74
8
        self.0
75
8
    }
76
}
77

            
78
/// Helper to define a set of tweak values as instances of `Encap`.
79
macro_rules! define_tweaks {
80
    {
81
        $(#[$pid_meta:meta])*
82
        PROTOID = $protoid:expr;
83
        $( $(#[$meta:meta])* $name:ident <= $suffix:expr ; )*
84
    } => {
85
        $(#[$pid_meta])*
86
        const PROTOID: &'static [u8] = $protoid.as_bytes();
87
        $(
88
            $(#[$meta])*
89
            const $name : Encap<'static> =
90
                Encap(concat!($protoid, ":", $suffix).as_bytes());
91
        )*
92
    }
93
}
94

            
95
define_tweaks! {
96
    /// Protocol ID: concatenated with other things in the protocol to
97
    /// prevent hash confusion.
98
    PROTOID =  "ntor3-curve25519-sha3_256-1";
99

            
100
    /// Message MAC tweak: used to compute the MAC of an encrypted client
101
    /// message.
102
    T_MSGMAC <= "msg_mac";
103
    /// Message KDF tweak: used when deriving keys for encrypting and MACing
104
    /// client message.
105
    T_MSGKDF <= "kdf_phase1";
106
    /// Key seeding tweak: used to derive final KDF input from secret_input.
107
    T_KEY_SEED <= "key_seed";
108
    /// Verifying tweak: used to derive 'verify' value from secret_input.
109
    T_VERIFY <= "verify";
110
    /// Final KDF tweak: used to derive keys for encrypting relay message
111
    /// and for the actual tor circuit.
112
    T_FINAL <= "kdf_final";
113
    /// Authentication tweak: used to derive the final authentication
114
    /// value for the handshake.
115
    T_AUTH <= "auth_final";
116
}
117

            
118
/// Compute a tweaked hash.
119
8
fn hash(t: &Encap<'_>, data: &[u8]) -> DigestVal {
120
8
    use digest::Digest;
121
8
    let mut d = Sha3_256::new();
122
8
    d.update((t.len() as u64).to_be_bytes());
123
8
    d.update(t.data());
124
8
    d.update(data);
125
8
    d.finalize().into()
126
8
}
127

            
128
/// Perform a symmetric encryption operation and return the encrypted data.
129
///
130
/// (This isn't safe to do more than once with the same key, but we never
131
/// do that in this protocol.)
132
8
fn encrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
133
8
    let mut d = m.to_vec();
134
8
    let zero_iv = GenericArray::default();
135
8
    let mut cipher = Aes256Ctr::new(key.into(), &zero_iv);
136
8
    cipher.apply_keystream(&mut d);
137
8
    d
138
8
}
139
/// Perform a symmetric decryption operation and return the encrypted data.
140
4
fn decrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
141
4
    encrypt(key, m)
142
4
}
143

            
144
/// Wrapper around a Digest or ExtendedOutput object that lets us use it
145
/// as a tor_bytes::Writer.
146
struct DigestWriter<U>(U);
147
impl<U: digest::Update> tor_bytes::Writer for DigestWriter<U> {
148
128
    fn write_all(&mut self, bytes: &[u8]) {
149
128
        self.0.update(bytes);
150
128
    }
151
}
152
impl<U> DigestWriter<U> {
153
    /// Consume this wrapper and return the underlying object.
154
16
    fn take(self) -> U {
155
16
        self.0
156
16
    }
157
}
158

            
159
/// Hash tweaked with T_KEY_SEED
160
4
fn h_key_seed(d: &[u8]) -> DigestVal {
161
4
    hash(&T_KEY_SEED, d)
162
4
}
163
/// Hash tweaked with T_VERIFY
164
4
fn h_verify(d: &[u8]) -> DigestVal {
165
4
    hash(&T_VERIFY, d)
166
4
}
167

            
168
/// Helper: compute the encryption key and mac_key for the client's
169
/// encrypted message.
170
///
171
/// Takes as inputs `xb` (the shared secret derived from
172
/// diffie-hellman as Bx or Xb), the relay's public key information,
173
/// the client's public key (B), and the shared verification string.
174
4
fn kdf_msgkdf(
175
4
    xb: &curve25519::SharedSecret,
176
4
    relay_public: &NtorV3PublicKey,
177
4
    client_public: &curve25519::PublicKey,
178
4
    verification: &[u8],
179
4
) -> (Zeroizing<EncKey>, DigestWriter<Sha3_256>) {
180
4
    // secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER)
181
4
    // phase1_keys = KDF_msgkdf(secret_input_phase1)
182
4
    // (ENC_K1, MAC_K1) = PARTITION(phase1_keys, ENC_KEY_LEN, MAC_KEY_LEN
183
4
    use digest::{ExtendableOutput, XofReader};
184
4
    let mut msg_kdf = DigestWriter(Shake256::default());
185
4
    msg_kdf.write(&T_MSGKDF);
186
4
    msg_kdf.write(xb);
187
4
    msg_kdf.write(&relay_public.id);
188
4
    msg_kdf.write(client_public);
189
4
    msg_kdf.write(&relay_public.pk);
190
4
    msg_kdf.write(PROTOID);
191
4
    msg_kdf.write(&Encap(verification));
192
4
    let mut r = msg_kdf.take().finalize_xof();
193
4
    let mut enc_key = Zeroizing::new([0; ENC_KEY_LEN]);
194
4
    let mut mac_key = Zeroizing::new([0; MAC_KEY_LEN]);
195
4

            
196
4
    r.read(&mut enc_key[..]);
197
4
    r.read(&mut mac_key[..]);
198
4
    let mut mac = DigestWriter(Sha3_256::default());
199
4
    {
200
4
        mac.write(&T_MSGMAC);
201
4
        mac.write(&Encap(&mac_key[..]));
202
4
        mac.write(&relay_public.id);
203
4
        mac.write(&relay_public.pk);
204
4
        mac.write(client_public);
205
4
    }
206
4

            
207
4
    (enc_key, mac)
208
4
}
209

            
210
/*
211
/// TODO
212
pub(crate) struct NtorV3Client {
213
    message: Vec<u8>,
214
}
215
*/
216

            
217
/// Key information about a relay used for the ntor v3 handshake.
218
///
219
/// Contains a single curve25519 ntor onion key, and the relay's ed25519
220
/// identity.
221
4
#[derive(Clone, Debug)]
222
pub(crate) struct NtorV3PublicKey {
223
    /// The relay's identity.
224
    id: Ed25519Identity,
225
    /// The relay's onion key.
226
    pk: curve25519::PublicKey,
227
}
228

            
229
/// Secret key information used by a relay for the ntor v3 handshake.
230
pub(crate) struct NtorV3SecretKey {
231
    /// The relay's public key information
232
    pk: NtorV3PublicKey,
233
    /// The secret onion key.
234
    sk: curve25519::StaticSecret,
235
}
236

            
237
impl NtorV3SecretKey {
238
    /// Checks whether `id` and `pk` match this secret key.
239
    ///
240
    /// Used to perform a constant-time secret key lookup.
241
2
    fn matches(&self, id: Ed25519Identity, pk: curve25519::PublicKey) -> Choice {
242
2
        // TODO: use similar pattern in ntor_v1!
243
2
        id.as_bytes().ct_eq(self.pk.id.as_bytes()) & pk.as_bytes().ct_eq(self.pk.pk.as_bytes())
244
2
    }
245
}
246

            
247
/// Client state for the ntor v3 handshake.
248
///
249
/// The client needs to hold this state between when it sends its part
250
/// of the handshake and when it receives the relay's reply.
251
pub(crate) struct NtorV3HandshakeState {
252
    /// The public key of the relay we're communicating with.
253
    relay_public: NtorV3PublicKey, // B, ID.
254
    /// Our ephemeral secret key for this handshake.
255
    my_sk: curve25519::StaticSecret, // x
256
    /// Our ephemeral public key for this handshake.
257
    my_public: curve25519::PublicKey, // X
258

            
259
    /// The shared secret generated as Bx or Xb.
260
    shared_secret: curve25519::SharedSecret, // Bx
261
    /// The MAC of our original encrypted message.
262
    msg_mac: MacVal, // msg_mac
263
}
264

            
265
/*
266
///
267
pub(crate) struct NtorV3KeyGenerator {
268
    seed: SecretBytes,
269
}
270
*/
271

            
272
/// Client-side Ntor version 3 handshake, part one.
273
///
274
/// Given a secure `rng`, a relay's public key, a secret message to send,
275
/// and a shared verification string, generate a new handshake state
276
/// and a message to send to the relay.
277
1
fn client_handshake_ntor_v3<R: RngCore + CryptoRng>(
278
1
    rng: &mut R,
279
1
    relay_public: &NtorV3PublicKey,
280
1
    client_msg: &[u8],
281
1
    verification: &[u8],
282
1
) -> (NtorV3HandshakeState, Vec<u8>) {
283
1
    let my_sk = curve25519::StaticSecret::new(rng.rng_compat());
284
1
    client_handshake_ntor_v3_no_keygen(relay_public, client_msg, verification, my_sk)
285
1
}
286

            
287
/// As `client_handshake_ntor_v3`, but don't generate an ephemeral DH
288
/// key: instead take that key an arguments `my_sk`.
289
2
fn client_handshake_ntor_v3_no_keygen(
290
2
    relay_public: &NtorV3PublicKey,
291
2
    client_msg: &[u8],
292
2
    verification: &[u8],
293
2
    my_sk: curve25519::StaticSecret,
294
2
) -> (NtorV3HandshakeState, Vec<u8>) {
295
2
    let my_public = curve25519::PublicKey::from(&my_sk);
296
2
    let bx = my_sk.diffie_hellman(&relay_public.pk);
297
2

            
298
2
    let (enc_key, mut mac) = kdf_msgkdf(&bx, relay_public, &my_public, verification);
299
2

            
300
2
    //encrypted_msg = ENC(ENC_K1, CM)
301
2
    // msg_mac = MAC_msgmac(MAC_K1, ID | B | X | encrypted_msg)
302
2
    let encrypted_msg = encrypt(&enc_key, client_msg);
303
2
    let msg_mac: DigestVal = {
304
2
        use digest::Digest;
305
2
        mac.write(&encrypted_msg);
306
2
        mac.take().finalize().into()
307
2
    };
308
2

            
309
2
    let mut message = Vec::new();
310
2
    message.write(&relay_public.id);
311
2
    message.write(&relay_public.pk);
312
2
    message.write(&my_public);
313
2
    message.write(&encrypted_msg);
314
2
    message.write(&msg_mac);
315
2

            
316
2
    let state = NtorV3HandshakeState {
317
2
        relay_public: relay_public.clone(),
318
2
        my_sk,
319
2
        my_public,
320
2
        shared_secret: bx,
321
2
        msg_mac,
322
2
    };
323
2

            
324
2
    (state, message)
325
2
}
326

            
327
/// Trait for an object that handle and incoming client message and
328
/// return a server's reply.
329
///
330
// TODO(nickm): I wanted to use a closure here, but the lifetimes didn't work,
331
// and I couldn't figure out why.
332
pub(crate) trait MsgReply {
333
    /// Given a message received from a client, parse it and decide
334
    /// how (and whether) to reply.
335
    ///
336
    /// Return None if the handshake should fail.
337
    fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>>;
338
}
339

            
340
/// Complete an ntor v3 handshake as a server.
341
///
342
/// Use the provided `rng` to generate keys; use the provided
343
/// `reply_fn` to handle incoming client secret message and decide how
344
/// to reply.  The client's handshake is in `message`.  Our private
345
/// key(s) are in `keys`.  The `verification` string must match the
346
/// string provided by the client.
347
///
348
/// On success, return the server handshake message to send, and an XofReader
349
/// to use in generating circuit keys.
350
1
fn server_handshake_ntor_v3<RNG: CryptoRng + RngCore, REPLY: MsgReply>(
351
1
    rng: &mut RNG,
352
1
    reply_fn: &mut REPLY,
353
1
    message: &[u8],
354
1
    keys: &[NtorV3SecretKey],
355
1
    verification: &[u8],
356
1
) -> RelayHandshakeResult<(Vec<u8>, impl digest::XofReader)> {
357
1
    let secret_key_y = curve25519::StaticSecret::new(rng.rng_compat());
358
1
    server_handshake_ntor_v3_no_keygen(reply_fn, &secret_key_y, message, keys, verification)
359
1
}
360

            
361
/// As `server_handshake_ntor_v3`, but take a secret key instead of an RNG.
362
2
fn server_handshake_ntor_v3_no_keygen<REPLY: MsgReply>(
363
2
    reply_fn: &mut REPLY,
364
2
    secret_key_y: &curve25519::StaticSecret,
365
2
    message: &[u8],
366
2
    keys: &[NtorV3SecretKey],
367
2
    verification: &[u8],
368
2
) -> RelayHandshakeResult<(Vec<u8>, impl digest::XofReader)> {
369
2
    // Decode the message.
370
2
    let mut r = Reader::from_slice(message);
371
2
    let id: Ed25519Identity = r.extract()?;
372
2
    let requested_pk: curve25519::PublicKey = r.extract()?;
373
2
    let client_pk: curve25519::PublicKey = r.extract()?;
374
2
    let client_msg = if let Some(msg_len) = r.remaining().checked_sub(MAC_LEN) {
375
2
        r.take(msg_len)?
376
    } else {
377
        return Err(tor_bytes::Error::Truncated.into());
378
    };
379
2
    let msg_mac: MacVal = r.extract()?;
380
2
    r.should_be_exhausted()?;
381

            
382
    // See if we recognize the provided (id,requested_pk) pair.
383
2
    let keypair = ct::lookup(keys, |key| key.matches(id, requested_pk));
384
2
    let keypair = match keypair {
385
2
        Some(k) => k,
386
        None => return Err(RelayHandshakeError::MissingKey),
387
    };
388

            
389
2
    let xb = keypair.sk.diffie_hellman(&client_pk);
390
2
    let (enc_key, mut mac) = kdf_msgkdf(&xb, &keypair.pk, &client_pk, verification);
391
2
    // Verify the message we received.
392
2
    let computed_mac: DigestVal = {
393
2
        use digest::Digest;
394
2
        mac.write(client_msg);
395
2
        mac.take().finalize().into()
396
2
    };
397
2
    let y_pk: curve25519::PublicKey = (secret_key_y).into();
398
2
    let xy = secret_key_y.diffie_hellman(&client_pk);
399
2

            
400
2
    let mut okay = computed_mac.ct_eq(&msg_mac)
401
2
        & ct::bool_to_choice(xy.was_contributory())
402
2
        & ct::bool_to_choice(xb.was_contributory());
403
2

            
404
2
    let plaintext_msg = decrypt(&enc_key, client_msg);
405
2

            
406
2
    // Handle the message and decide how to reply.
407
2
    let reply = reply_fn.reply(&plaintext_msg);
408
2

            
409
2
    // It's not exactly constant time to use is_some() and
410
2
    // unwrap_or_else() here, but that should be somewhat
411
2
    // hidden by the rest of the computation.
412
2
    okay &= ct::bool_to_choice(reply.is_some());
413
2
    let reply = reply.unwrap_or_default();
414
2

            
415
2
    // If we reach this point, we are actually replying, or pretending
416
2
    // that we're going to reply.
417
2

            
418
2
    let secret_input = {
419
2
        let mut si = Zeroizing::new(Vec::new());
420
2
        si.write(&xy);
421
2
        si.write(&xb);
422
2
        si.write(&keypair.pk.id);
423
2
        si.write(&keypair.pk.pk);
424
2
        si.write(&client_pk);
425
2
        si.write(&y_pk);
426
2
        si.write(PROTOID);
427
2
        si.write(&Encap(verification));
428
2
        si
429
2
    };
430
2
    let ntor_key_seed = h_key_seed(&secret_input);
431
2
    let verify = h_verify(&secret_input);
432
2

            
433
2
    let (enc_key, keystream) = {
434
2
        use digest::{ExtendableOutput, XofReader};
435
2
        let mut xof = DigestWriter(Shake256::default());
436
2
        xof.write(&T_FINAL);
437
2
        xof.write(&ntor_key_seed);
438
2
        let mut r = xof.take().finalize_xof();
439
2
        let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
440
2
        r.read(&mut enc_key[..]);
441
2
        (enc_key, r)
442
2
    };
443
2
    let encrypted_reply = encrypt(&enc_key, &reply);
444
2
    let auth: DigestVal = {
445
2
        use digest::Digest;
446
2
        let mut auth = DigestWriter(Sha3_256::default());
447
2
        auth.write(&T_AUTH);
448
2
        auth.write(&verify);
449
2
        auth.write(&keypair.pk.id);
450
2
        auth.write(&keypair.pk.pk);
451
2
        auth.write(&y_pk);
452
2
        auth.write(&client_pk);
453
2
        auth.write(&msg_mac);
454
2
        auth.write(&Encap(&encrypted_reply));
455
2
        auth.write(PROTOID);
456
2
        auth.write(&b"Server"[..]);
457
2
        auth.take().finalize().into()
458
2
    };
459
2

            
460
2
    let reply = {
461
2
        let mut reply = Vec::new();
462
2
        reply.write(&y_pk);
463
2
        reply.write(&auth);
464
2
        reply.write(&encrypted_reply);
465
2
        reply
466
2
    };
467
2

            
468
2
    if okay.into() {
469
2
        Ok((reply, keystream))
470
    } else {
471
        Err(RelayHandshakeError::BadHandshake)
472
    }
473
2
}
474

            
475
/// Finalize the handshake on the client side.
476
///
477
/// Called after we've received a message from the relay: try to
478
/// complete the handshake and verify its correctness.
479
///
480
/// On success, return the server's reply to our original encrypted message,
481
/// and an `XofReader` to use in generating circuit keys.
482
2
fn client_handshake_ntor_v3_part2(
483
2
    state: &NtorV3HandshakeState,
484
2
    relay_handshake: &[u8],
485
2
    verification: &[u8],
486
2
) -> Result<(Vec<u8>, impl digest::XofReader)> {
487
2
    let mut reader = Reader::from_slice(relay_handshake);
488
2
    let y_pk: curve25519::PublicKey = reader.extract()?;
489
2
    let auth: DigestVal = reader.extract()?;
490
2
    let encrypted_msg = reader.into_rest();
491
2

            
492
2
    let yx = state.my_sk.diffie_hellman(&y_pk);
493
2
    let secret_input = {
494
2
        let mut si = Zeroizing::new(Vec::new());
495
2
        si.write(&yx);
496
2
        si.write(&state.shared_secret);
497
2
        si.write(&state.relay_public.id);
498
2
        si.write(&state.relay_public.pk);
499
2
        si.write(&state.my_public);
500
2
        si.write(&y_pk);
501
2
        si.write(PROTOID);
502
2
        si.write(&Encap(verification));
503
2
        si
504
2
    };
505
2
    let ntor_key_seed = h_key_seed(&secret_input);
506
2
    let verify = h_verify(&secret_input);
507
2

            
508
2
    let computed_auth: DigestVal = {
509
2
        use digest::Digest;
510
2
        let mut auth = DigestWriter(Sha3_256::default());
511
2
        auth.write(&T_AUTH);
512
2
        auth.write(&verify);
513
2
        auth.write(&state.relay_public.id);
514
2
        auth.write(&state.relay_public.pk);
515
2
        auth.write(&y_pk);
516
2
        auth.write(&state.my_public);
517
2
        auth.write(&state.msg_mac);
518
2
        auth.write(&Encap(encrypted_msg));
519
2
        auth.write(PROTOID);
520
2
        auth.write(&b"Server"[..]);
521
2
        auth.take().finalize().into()
522
2
    };
523
2

            
524
2
    let okay = computed_auth.ct_eq(&auth)
525
2
        & ct::bool_to_choice(yx.was_contributory())
526
2
        & ct::bool_to_choice(state.shared_secret.was_contributory());
527
2

            
528
2
    let (enc_key, keystream) = {
529
2
        use digest::{ExtendableOutput, XofReader};
530
2
        let mut xof = DigestWriter(Shake256::default());
531
2
        xof.write(&T_FINAL);
532
2
        xof.write(&ntor_key_seed);
533
2
        let mut r = xof.take().finalize_xof();
534
2
        let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
535
2
        r.read(&mut enc_key[..]);
536
2
        (enc_key, r)
537
2
    };
538
2
    let server_reply = decrypt(&enc_key, encrypted_msg);
539
2

            
540
2
    if okay.into() {
541
2
        Ok((server_reply, keystream))
542
    } else {
543
        Err(Error::BadCircHandshake)
544
    }
545
2
}
546

            
547
/*
548
impl super::ClientHandshake for NtorV3Client {
549
    type KeyType = NtorPublicKey;
550
    type StateType = NtorV3HandshakeState;
551
    type KeyGen = NtorV3KeyGenerator;
552

            
553

            
554
}
555
*/
556

            
557
#[cfg(test)]
558
#[allow(non_snake_case)] // to enable variable names matching the spec.
559
#[allow(clippy::many_single_char_names)] // ibid
560
#[allow(clippy::unwrap_used)]
561
mod test {
562
    use super::*;
563
    use hex_literal::hex;
564

            
565
    #[test]
566
    fn test_ntor3_roundtrip() {
567
        let b = curve25519::StaticSecret::new(rand::thread_rng().rng_compat());
568
        let mut rng = rand::thread_rng();
569
        let id = b"not identifier---but correct len";
570

            
571
        let B: curve25519::PublicKey = (&b).into();
572
        let relay_public = NtorV3PublicKey {
573
            pk: B,
574
            id: (*id).into(),
575
        };
576
        let relay_private = NtorV3SecretKey {
577
            pk: relay_public.clone(),
578
            sk: b,
579
        };
580

            
581
        let verification = &b"shared secret"[..];
582
        let client_message = &b"Hello. I am a client. Let's be friends!"[..];
583
        let relay_message = &b"Greetings, client. I am a robot. Beep boop."[..];
584

            
585
        let (c_state, c_handshake) =
586
            client_handshake_ntor_v3(&mut rng, &relay_public, client_message, verification);
587

            
588
        struct Rep(Vec<u8>, Vec<u8>);
589
        impl MsgReply for Rep {
590
            fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
591
                self.0 = msg.to_vec();
592
                Some(self.1.clone())
593
            }
594
        }
595
        let mut rep = Rep(Vec::new(), relay_message.to_vec());
596

            
597
        let (s_handshake, mut s_keygen) = server_handshake_ntor_v3(
598
            &mut rng,
599
            &mut rep,
600
            &c_handshake,
601
            &[relay_private],
602
            verification,
603
        )
604
        .unwrap();
605

            
606
        let (s_msg, mut c_keygen) =
607
            client_handshake_ntor_v3_part2(&c_state, &s_handshake, verification).unwrap();
608

            
609
        assert_eq!(rep.0[..], client_message[..]);
610
        assert_eq!(s_msg[..], relay_message[..]);
611
        use digest::XofReader;
612
        let mut s_keys = [0_u8; 100];
613
        let mut c_keys = [0_u8; 1000];
614
        s_keygen.read(&mut s_keys);
615
        c_keygen.read(&mut c_keys);
616
        assert_eq!(s_keys[..], c_keys[..100]);
617
    }
618

            
619
    #[test]
620
    fn test_ntor3_testvec() {
621
        let b = hex!("4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
622
        let id = hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
623
        let x = hex!("b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49");
624
        let y = hex!("4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053");
625
        let b: curve25519::StaticSecret = b.into();
626
        let B: curve25519::PublicKey = (&b).into();
627
        let id: Ed25519Identity = id.into();
628
        let x: curve25519::StaticSecret = x.into();
629
        //let X = (&x).into();
630
        let y: curve25519::StaticSecret = y.into();
631

            
632
        let client_message = hex!("68656c6c6f20776f726c64");
633
        let verification = hex!("78797a7a79");
634
        let server_message = hex!("486f6c61204d756e646f");
635

            
636
        let relay_public = NtorV3PublicKey { pk: B, id };
637
        let relay_private = NtorV3SecretKey {
638
            sk: b,
639
            pk: relay_public.clone(),
640
        };
641

            
642
        let (state, client_handshake) =
643
            client_handshake_ntor_v3_no_keygen(&relay_public, &client_message, &verification, x);
644

            
645
        assert_eq!(client_handshake[..], hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea65db8be9c72b68cd461942088502f67")[..]);
646

            
647
        struct Replier(Vec<u8>, Vec<u8>, bool);
648
        impl MsgReply for Replier {
649
            fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
650
                assert_eq!(msg, &self.0);
651
                self.2 = true;
652
                Some(self.1.clone())
653
            }
654
        }
655
        let mut rep = Replier(client_message.to_vec(), server_message.to_vec(), false);
656

            
657
        let (server_handshake, mut server_keygen) = server_handshake_ntor_v3_no_keygen(
658
            &mut rep,
659
            &y,
660
            &client_handshake,
661
            &[relay_private],
662
            &verification,
663
        )
664
        .unwrap();
665
        assert!(rep.2);
666

            
667
        assert_eq!(server_handshake[..], hex!("4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461ab130c5b18ab0a91276651202c3e1e87c0d32054c")[..]);
668

            
669
        let (server_msg_received, mut client_keygen) =
670
            client_handshake_ntor_v3_part2(&state, &server_handshake, &verification).unwrap();
671
        assert_eq!(&server_msg_received, &server_message);
672

            
673
        let (c_keys, s_keys) = {
674
            use digest::XofReader;
675
            let mut c = [0_u8; 256];
676
            let mut s = [0_u8; 256];
677
            client_keygen.read(&mut c);
678
            server_keygen.read(&mut s);
679
            (c, s)
680
        };
681
        assert_eq!(c_keys, s_keys);
682
        assert_eq!(c_keys[..], hex!("9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00fa8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b09749b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fcff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a")[..]);
683
    }
684
}