1
//! Relay cell cryptography
2
//!
3
//! The Tor protocol centers around "RELAY cells", which are
4
//! transmitted through the network along circuits.  The client that
5
//! creates a circuit shares two different set of keys and state with
6
//! each of the relays on the circuit: one for "outbound" traffic, and
7
//! one for "inbound" traffic.
8
//!
9

            
10
use crate::{Error, Result};
11
use std::convert::TryInto;
12
use tor_cell::chancell::RawCellBody;
13
use tor_error::internal;
14

            
15
use generic_array::GenericArray;
16

            
17
/// Type for the body of a relay cell.
18
#[derive(Clone)]
19
pub(crate) struct RelayCellBody(RawCellBody);
20

            
21
impl From<RawCellBody> for RelayCellBody {
22
3195
    fn from(body: RawCellBody) -> Self {
23
3195
        RelayCellBody(body)
24
3195
    }
25
}
26
impl From<RelayCellBody> for RawCellBody {
27
2544
    fn from(cell: RelayCellBody) -> Self {
28
2544
        cell.0
29
2544
    }
30
}
31
impl AsRef<[u8]> for RelayCellBody {
32
905
    fn as_ref(&self) -> &[u8] {
33
905
        &self.0[..]
34
905
    }
35
}
36
impl AsMut<[u8]> for RelayCellBody {
37
1794
    fn as_mut(&mut self) -> &mut [u8] {
38
1794
        &mut self.0[..]
39
1794
    }
40
}
41

            
42
/// Represents the ability for a circuit crypto state to be initialized
43
/// from a given seed.
44
pub(crate) trait CryptInit: Sized {
45
    /// Return the number of bytes that this state will require.
46
    fn seed_len() -> usize;
47
    /// Construct this state from a seed of the appropriate length.
48
    fn initialize(seed: &[u8]) -> Result<Self>;
49
    /// Initialize this object from a key generator.
50
18
    fn construct<K: super::handshake::KeyGenerator>(keygen: K) -> Result<Self> {
51
18
        let seed = keygen.expand(Self::seed_len())?;
52
18
        Self::initialize(&seed)
53
18
    }
54
}
55

            
56
/// A paired object containing an inbound client layer and an outbound
57
/// client layer.
58
///
59
/// TODO: Maybe we should fold this into CryptInit.
60
pub(crate) trait ClientLayer<F, B>
61
where
62
    F: OutboundClientLayer,
63
    B: InboundClientLayer,
64
{
65
    /// Consume this ClientLayer and return a paired forward and reverse
66
    /// crypto layer.
67
    fn split(self) -> (F, B);
68
}
69

            
70
/// Represents a relay's view of the crypto state on a given circuit.
71
pub(crate) trait RelayCrypt {
72
    /// Prepare a RelayCellBody to be sent towards the client.
73
    fn originate(&mut self, cell: &mut RelayCellBody);
74
    /// Encrypt a RelayCellBody that is moving towards the client.
75
    fn encrypt_inbound(&mut self, cell: &mut RelayCellBody);
76
    /// Decrypt a RelayCellBody that is moving towards the client.
77
    ///
78
    /// Return true if it is addressed to us.
79
    fn decrypt_outbound(&mut self, cell: &mut RelayCellBody) -> bool;
80
}
81

            
82
/// A client's view of the crypto state shared with a single relay, as
83
/// used for outbound cells.
84
pub(crate) trait OutboundClientLayer {
85
    /// Prepare a RelayCellBody to be sent to the relay at this layer, and
86
    /// encrypt it.
87
    ///
88
    /// Return the authentication tag.
89
    fn originate_for(&mut self, cell: &mut RelayCellBody) -> &[u8];
90
    /// Encrypt a RelayCellBody to be decrypted by this layer.
91
    fn encrypt_outbound(&mut self, cell: &mut RelayCellBody);
92
}
93

            
94
/// A client's view of the crypto state shared with a single relay, as
95
/// used for inbound cells.
96
pub(crate) trait InboundClientLayer {
97
    /// Decrypt a CellBody that passed through this layer.
98
    ///
99
    /// Return an authentication tag if this layer is the originator.
100
    fn decrypt_inbound(&mut self, cell: &mut RelayCellBody) -> Option<&[u8]>;
101
}
102

            
103
/// Type to store hop indices on a circuit.
104
///
105
/// Hop indices are zero-based: "0" denotes the first hop on the circuit.
106
315
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
107
pub(crate) struct HopNum(u8);
108

            
109
impl From<HopNum> for u8 {
110
105
    fn from(hop: HopNum) -> u8 {
111
105
        hop.0
112
105
    }
113
}
114

            
115
impl From<u8> for HopNum {
116
9245
    fn from(v: u8) -> HopNum {
117
9245
        HopNum(v)
118
9245
    }
119
}
120

            
121
impl From<HopNum> for usize {
122
7679
    fn from(hop: HopNum) -> usize {
123
7679
        hop.0 as usize
124
7679
    }
125
}
126

            
127
impl std::fmt::Display for HopNum {
128
4
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
129
4
        self.0.fmt(f)
130
4
    }
131
}
132

            
133
/// A client's view of the cryptographic state for an entire
134
/// constructed circuit, as used for sending cells.
135
pub(crate) struct OutboundClientCrypt {
136
    /// Vector of layers, one for each hop on the circuit, ordered from the
137
    /// closest hop to the farthest.
138
    layers: Vec<Box<dyn OutboundClientLayer + Send>>,
139
}
140

            
141
/// A client's view of the cryptographic state for an entire
142
/// constructed circuit, as used for receiving cells.
143
pub(crate) struct InboundClientCrypt {
144
    /// Vector of layers, one for each hop on the circuit, ordered from the
145
    /// closest hop to the farthest.
146
    layers: Vec<Box<dyn InboundClientLayer + Send>>,
147
}
148

            
149
impl OutboundClientCrypt {
150
    /// Return a new (empty) OutboundClientCrypt.
151
50
    pub(crate) fn new() -> Self {
152
50
        OutboundClientCrypt { layers: Vec::new() }
153
50
    }
154
    /// Prepare a cell body to sent away from the client.
155
    ///
156
    /// The cell is prepared for the `hop`th hop, and then encrypted with
157
    /// the appropriate keys.
158
    ///
159
    /// On success, returns a reference to tag that should be expected
160
    /// for an authenticated SENDME sent in response to this cell.
161
2799
    pub(crate) fn encrypt(&mut self, cell: &mut RelayCellBody, hop: HopNum) -> Result<&[u8; 20]> {
162
2799
        let hop: usize = hop.into();
163
2799
        if hop >= self.layers.len() {
164
1
            return Err(Error::NoSuchHop);
165
2798
        }
166
2798

            
167
2798
        let mut layers = self.layers.iter_mut().take(hop + 1).rev();
168
2798
        let first_layer = layers.next().ok_or(Error::NoSuchHop)?;
169
2798
        let tag = first_layer.originate_for(cell);
170
8394
        for layer in layers {
171
5596
            layer.encrypt_outbound(cell);
172
5596
        }
173
2798
        Ok(tag.try_into().expect("wrong SENDME digest size"))
174
2799
    }
175

            
176
    /// Add a new layer to this OutboundClientCrypt
177
124
    pub(crate) fn add_layer(&mut self, layer: Box<dyn OutboundClientLayer + Send>) {
178
124
        assert!(self.layers.len() < std::u8::MAX as usize);
179
124
        self.layers.push(layer);
180
124
    }
181

            
182
    /// Return the number of layers configured on this OutboundClientCrypt.
183
21
    pub(crate) fn n_layers(&self) -> usize {
184
21
        self.layers.len()
185
21
    }
186
}
187

            
188
impl InboundClientCrypt {
189
    /// Return a new (empty) InboundClientCrypt.
190
50
    pub(crate) fn new() -> Self {
191
50
        InboundClientCrypt { layers: Vec::new() }
192
50
    }
193
    /// Decrypt an incoming cell that is coming to the client.
194
    ///
195
    /// On success, return which hop was the originator of the cell.
196
    // TODO(nickm): Use a real type for the tag, not just `&[u8]`.
197
348
    pub(crate) fn decrypt(&mut self, cell: &mut RelayCellBody) -> Result<(HopNum, &[u8])> {
198
1040
        for (hopnum, layer) in self.layers.iter_mut().enumerate() {
199
1040
            if let Some(tag) = layer.decrypt_inbound(cell) {
200
347
                assert!(hopnum <= std::u8::MAX as usize);
201
347
                return Ok(((hopnum as u8).into(), tag));
202
693
            }
203
        }
204
1
        Err(Error::BadCellAuth)
205
348
    }
206
    /// Add a new layer to this InboundClientCrypt
207
124
    pub(crate) fn add_layer(&mut self, layer: Box<dyn InboundClientLayer + Send>) {
208
124
        assert!(self.layers.len() < std::u8::MAX as usize);
209
124
        self.layers.push(layer);
210
124
    }
211

            
212
    /// Return the number of layers configured on this InboundClientCrypt.
213
    ///
214
    /// TODO: use HopNum
215
    #[allow(dead_code)]
216
1
    pub(crate) fn n_layers(&self) -> usize {
217
1
        self.layers.len()
218
1
    }
219
}
220

            
221
/// Standard Tor relay crypto, as instantiated for RELAY cells.
222
pub(crate) type Tor1RelayCrypto =
223
    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes128Ctr, tor_llcrypto::d::Sha1>;
224

            
225
/// Incomplete untested implementation of Tor's current cell crypto.
226
pub(crate) mod tor1 {
227
    use super::*;
228
    use cipher::{NewCipher, StreamCipher};
229
    use digest::Digest;
230
    use std::convert::TryInto;
231
    use typenum::Unsigned;
232

            
233
    /// A CryptState is part of a RelayCrypt or a ClientLayer.
234
    ///
235
    /// It is parameterized on a stream cipher and a digest type: most
236
    /// circuits will use AES-128-CTR and SHA1, but v3 onion services
237
    /// use AES-256-CTR and SHA-3.
238
    pub(crate) struct CryptState<SC: StreamCipher, D: Digest + Clone> {
239
        /// Stream cipher for en/decrypting cell bodies.
240
        cipher: SC,
241
        /// Digest for authenticating cells to/from this hop.
242
        digest: D,
243
        /// Most recent digest value generated by this crypto.
244
        last_digest_val: GenericArray<u8, D::OutputSize>,
245
    }
246

            
247
    /// A pair of CryptStates, one for the forward (away from client)
248
    /// direction, and one for the reverse (towards client) direction.
249
    pub(crate) struct CryptStatePair<SC: StreamCipher, D: Digest + Clone> {
250
        /// State for en/decrypting cells sent away from the client.
251
        fwd: CryptState<SC, D>,
252
        /// State for en/decrypting cells sent towards the client.
253
        back: CryptState<SC, D>,
254
    }
255

            
256
    impl<SC: StreamCipher + NewCipher, D: Digest + Clone> CryptInit for CryptStatePair<SC, D> {
257
39
        fn seed_len() -> usize {
258
39
            SC::KeySize::to_usize() * 2 + D::OutputSize::to_usize() * 2
259
39
        }
260
21
        fn initialize(seed: &[u8]) -> Result<Self> {
261
21
            if seed.len() != Self::seed_len() {
262
                return Err(Error::from(internal!(
263
                    "seed length {} was invalid",
264
                    seed.len()
265
                )));
266
21
            }
267
21
            let keylen = SC::KeySize::to_usize();
268
21
            let dlen = D::OutputSize::to_usize();
269
21
            let fdinit = &seed[0..dlen];
270
21
            let bdinit = &seed[dlen..dlen * 2];
271
21
            let fckey = &seed[dlen * 2..dlen * 2 + keylen];
272
21
            let bckey = &seed[dlen * 2 + keylen..dlen * 2 + keylen * 2];
273
21
            let fwd = CryptState {
274
21
                cipher: SC::new(fckey.try_into().expect("Wrong length"), &Default::default()),
275
21
                digest: D::new().chain_update(fdinit),
276
21
                last_digest_val: GenericArray::default(),
277
21
            };
278
21
            let back = CryptState {
279
21
                cipher: SC::new(bckey.try_into().expect("Wrong length"), &Default::default()),
280
21
                digest: D::new().chain_update(bdinit),
281
21
                last_digest_val: GenericArray::default(),
282
21
            };
283
21
            Ok(CryptStatePair { fwd, back })
284
21
        }
285
    }
286

            
287
    impl<SC, D> ClientLayer<CryptState<SC, D>, CryptState<SC, D>> for CryptStatePair<SC, D>
288
    where
289
        SC: StreamCipher,
290
        D: Digest + Clone,
291
    {
292
18
        fn split(self) -> (CryptState<SC, D>, CryptState<SC, D>) {
293
18
            (self.fwd, self.back)
294
18
        }
295
    }
296

            
297
    impl<SC: StreamCipher, D: Digest + Clone> RelayCrypt for CryptStatePair<SC, D> {
298
299
        fn originate(&mut self, cell: &mut RelayCellBody) {
299
299
            let mut d_ignored = GenericArray::default();
300
299
            cell.set_digest(&mut self.back.digest, &mut d_ignored);
301
299
        }
302
897
        fn encrypt_inbound(&mut self, cell: &mut RelayCellBody) {
303
897
            self.back.cipher.apply_keystream(cell.as_mut());
304
897
        }
305
897
        fn decrypt_outbound(&mut self, cell: &mut RelayCellBody) -> bool {
306
897
            self.fwd.cipher.apply_keystream(cell.as_mut());
307
897
            let mut d_ignored = GenericArray::default();
308
897
            cell.recognized(&mut self.fwd.digest, &mut d_ignored)
309
897
        }
310
    }
311

            
312
    impl<SC: StreamCipher, D: Digest + Clone> OutboundClientLayer for CryptState<SC, D> {
313
350
        fn originate_for(&mut self, cell: &mut RelayCellBody) -> &[u8] {
314
350
            cell.set_digest(&mut self.digest, &mut self.last_digest_val);
315
350
            self.encrypt_outbound(cell);
316
350
            &self.last_digest_val
317
350
        }
318
1050
        fn encrypt_outbound(&mut self, cell: &mut RelayCellBody) {
319
1050
            self.cipher.apply_keystream(&mut cell.0[..]);
320
1050
        }
321
    }
322

            
323
    impl<SC: StreamCipher, D: Digest + Clone> InboundClientLayer for CryptState<SC, D> {
324
900
        fn decrypt_inbound(&mut self, cell: &mut RelayCellBody) -> Option<&[u8]> {
325
900
            self.cipher.apply_keystream(&mut cell.0[..]);
326
900
            if cell.recognized(&mut self.digest, &mut self.last_digest_val) {
327
299
                Some(&self.last_digest_val)
328
            } else {
329
601
                None
330
            }
331
900
        }
332
    }
333

            
334
    impl RelayCellBody {
335
        /// Prepare a cell body by setting its digest and recognized field.
336
649
        fn set_digest<D: Digest + Clone>(
337
649
            &mut self,
338
649
            d: &mut D,
339
649
            used_digest: &mut GenericArray<u8, D::OutputSize>,
340
649
        ) {
341
649
            self.0[1] = 0;
342
649
            self.0[2] = 0;
343
649
            self.0[5] = 0;
344
649
            self.0[6] = 0;
345
649
            self.0[7] = 0;
346
649
            self.0[8] = 0;
347
649

            
348
649
            d.update(&self.0[..]);
349
649
            // TODO(nickm) can we avoid this clone?  Probably not.
350
649
            *used_digest = d.clone().finalize();
351
649
            self.0[5..9].copy_from_slice(&used_digest[0..4]);
352
649
        }
353
        /// Check a cell to see whether its recognized field is set.
354
1797
        fn recognized<D: Digest + Clone>(
355
1797
            &self,
356
1797
            d: &mut D,
357
1797
            rcvd: &mut GenericArray<u8, D::OutputSize>,
358
1797
        ) -> bool {
359
1797
            use crate::util::ct;
360
1797
            use arrayref::array_ref;
361
1797

            
362
1797
            // Validate 'Recognized' field
363
1797
            let recognized = u16::from_be_bytes(*array_ref![self.0, 1, 2]);
364
1797
            if recognized != 0 {
365
1199
                return false;
366
598
            }
367
598

            
368
598
            // Now also validate the 'Digest' field:
369
598

            
370
598
            let mut dtmp = d.clone();
371
598
            // Add bytes up to the 'Digest' field
372
598
            dtmp.update(&self.0[..5]);
373
598
            // Add zeroes where the 'Digest' field is
374
598
            dtmp.update([0_u8; 4]);
375
598
            // Add the rest of the bytes
376
598
            dtmp.update(&self.0[9..]);
377
598
            // Clone the digest before finalize destroys it because we will use
378
598
            // it in the future
379
598
            let dtmp_clone = dtmp.clone();
380
598
            let result = dtmp.finalize();
381
598

            
382
598
            if ct::bytes_eq(&self.0[5..9], &result[0..4]) {
383
                // Copy useful things out of this cell (we keep running digest)
384
598
                *d = dtmp_clone;
385
598
                *rcvd = result;
386
598
                return true;
387
            }
388

            
389
            false
390
1797
        }
391
    }
392
}
393

            
394
#[cfg(test)]
395
mod test {
396
    #![allow(clippy::unwrap_used)]
397
    use super::*;
398
    use crate::SecretBytes;
399
    use rand::RngCore;
400

            
401
    fn add_layers(
402
        cc_out: &mut OutboundClientCrypt,
403
        cc_in: &mut InboundClientCrypt,
404
        pair: Tor1RelayCrypto,
405
    ) {
406
        let (outbound, inbound) = pair.split();
407
        cc_out.add_layer(Box::new(outbound));
408
        cc_in.add_layer(Box::new(inbound));
409
    }
410

            
411
    #[test]
412
    fn roundtrip() {
413
        // Take canned keys and make sure we can do crypto correctly.
414
        use crate::crypto::handshake::ShakeKeyGenerator as KGen;
415
        fn s(seed: &[u8]) -> SecretBytes {
416
            let mut s: SecretBytes = SecretBytes::new(Vec::new());
417
            s.extend(seed);
418
            s
419
        }
420

            
421
        let seed1 = s(b"hidden we are free");
422
        let seed2 = s(b"free to speak, to free ourselves");
423
        let seed3 = s(b"free to hide no more");
424

            
425
        let mut cc_out = OutboundClientCrypt::new();
426
        let mut cc_in = InboundClientCrypt::new();
427
        let pair = Tor1RelayCrypto::construct(KGen::new(seed1.clone())).unwrap();
428
        add_layers(&mut cc_out, &mut cc_in, pair);
429
        let pair = Tor1RelayCrypto::construct(KGen::new(seed2.clone())).unwrap();
430
        add_layers(&mut cc_out, &mut cc_in, pair);
431
        let pair = Tor1RelayCrypto::construct(KGen::new(seed3.clone())).unwrap();
432
        add_layers(&mut cc_out, &mut cc_in, pair);
433

            
434
        assert_eq!(cc_in.n_layers(), 3);
435
        assert_eq!(cc_out.n_layers(), 3);
436

            
437
        let mut r1 = Tor1RelayCrypto::construct(KGen::new(seed1)).unwrap();
438
        let mut r2 = Tor1RelayCrypto::construct(KGen::new(seed2)).unwrap();
439
        let mut r3 = Tor1RelayCrypto::construct(KGen::new(seed3)).unwrap();
440

            
441
        let mut rng = rand::thread_rng();
442
        for _ in 1..300 {
443
            // outbound cell
444
            let mut cell = [0_u8; 509];
445
            let mut cell_orig = [0_u8; 509];
446
            rng.fill_bytes(&mut cell_orig);
447
            cell.copy_from_slice(&cell_orig);
448
            let mut cell = cell.into();
449
            let _tag = cc_out.encrypt(&mut cell, 2.into()).unwrap();
450
            assert_ne!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
451
            assert!(!r1.decrypt_outbound(&mut cell));
452
            assert!(!r2.decrypt_outbound(&mut cell));
453
            assert!(r3.decrypt_outbound(&mut cell));
454

            
455
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
456

            
457
            // inbound cell
458
            let mut cell = [0_u8; 509];
459
            let mut cell_orig = [0_u8; 509];
460
            rng.fill_bytes(&mut cell_orig);
461
            cell.copy_from_slice(&cell_orig);
462
            let mut cell = cell.into();
463

            
464
            r3.originate(&mut cell);
465
            r3.encrypt_inbound(&mut cell);
466
            r2.encrypt_inbound(&mut cell);
467
            r1.encrypt_inbound(&mut cell);
468
            let (layer, _tag) = cc_in.decrypt(&mut cell).unwrap();
469
            assert_eq!(layer, 2.into());
470
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
471

            
472
            // TODO: Test tag somehow.
473
        }
474

            
475
        // Try a failure: sending a cell to a nonexistent hop.
476
        {
477
            let mut cell = [0_u8; 509].into();
478
            let err = cc_out.encrypt(&mut cell, 10.into());
479
            assert!(matches!(err, Err(Error::NoSuchHop)));
480
        }
481

            
482
        // Try a failure: A junk cell with no correct auth from any layer.
483
        {
484
            let mut cell = [0_u8; 509].into();
485
            let err = cc_in.decrypt(&mut cell);
486
            assert!(matches!(err, Err(Error::BadCellAuth)));
487
        }
488
    }
489

            
490
    // From tor's test_relaycrypt.c
491

            
492
    #[test]
493
    fn testvec() {
494
        use digest::XofReader;
495
        use digest::{ExtendableOutput, Update};
496

            
497
        const K1: &[u8; 72] =
498
            b"    'My public key is in this signed x509 object', said Tom assertively.";
499
        const K2: &[u8; 72] =
500
            b"'Let's chart the pedal phlanges in the tomb', said Tom cryptographically";
501
        const K3: &[u8; 72] =
502
            b"     'Segmentation fault bugs don't _just happen_', said Tom seethingly.";
503

            
504
        const SEED: &[u8;108] = b"'You mean to tell me that there's a version of Sha-3 with no limit on the output length?', said Tom shakily.";
505

            
506
        // These test vectors were generated from Tor.
507
        let data: &[(usize, &str)] = &include!("../../testdata/cell_crypt.data");
508

            
509
        let mut cc_out = OutboundClientCrypt::new();
510
        let mut cc_in = InboundClientCrypt::new();
511
        let pair = Tor1RelayCrypto::initialize(&K1[..]).unwrap();
512
        add_layers(&mut cc_out, &mut cc_in, pair);
513
        let pair = Tor1RelayCrypto::initialize(&K2[..]).unwrap();
514
        add_layers(&mut cc_out, &mut cc_in, pair);
515
        let pair = Tor1RelayCrypto::initialize(&K3[..]).unwrap();
516
        add_layers(&mut cc_out, &mut cc_in, pair);
517

            
518
        let mut xof = tor_llcrypto::d::Shake256::default();
519
        xof.update(&SEED[..]);
520
        let mut stream = xof.finalize_xof();
521

            
522
        let mut j = 0;
523
        for cellno in 0..51 {
524
            let mut body = [0_u8; 509];
525
            body[0] = 2; // command: data.
526
            body[4] = 1; // streamid: 1.
527
            body[9] = 1; // length: 498
528
            body[10] = 242;
529
            stream.read(&mut body[11..]);
530

            
531
            let mut cell = body.into();
532
            let _ = cc_out.encrypt(&mut cell, 2.into());
533

            
534
            if cellno == data[j].0 {
535
                let expected = hex::decode(data[j].1).unwrap();
536
                assert_eq!(cell.as_ref(), &expected[..]);
537
                j += 1;
538
            }
539
        }
540
    }
541
}