1
//! Implementation for Counter Galois Onion (CGO) relay cell encryption
2
//!
3
//! CGO is an improved approach for encrypting relay cells, with better support
4
//! for tagging resistance, better forward secrecy, and other improvements.
5
//! It is described in [a paper][CGO] by Degabriele, Melloni, Münch, and Stam,
6
//! and specified in [proposal 359].
7
//!
8
//! CGO is based on a construction called "UIV+",
9
//! which provides the "robust pseudorandom permutation" security definition.
10
//! Notably, _encryption_ with UIV+ is non-malleable (and hence tagging resistant),
11
//! whereas _decryption_ with UIV+ is malleable (and hence not tagging resistant).
12
//!
13
//! [CGO]: https://eprint.iacr.org/2025/583
14
//! [proposal 359]: https://spec.torproject.org/proposals/359-cgo-redux.html
15
//
16
// Implementation note: For naming, I'm trying to use the symbols from the paper
17
// and the spec (which should be the same) wherever possible.
18

            
19
#![allow(dead_code)] // TODO CGO: Remove this once we actually use CGO encryption.
20

            
21
use aes::{Aes128, Aes128Dec, Aes128Enc, Aes256, Aes256Dec, Aes256Enc};
22
use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, BlockSizeUser, StreamCipher as _};
23
use digest::KeyInit;
24
use polyval::{Polyval, universal_hash::UniversalHash};
25
use tor_cell::{
26
    chancell::{CELL_DATA_LEN, ChanCmd},
27
    relaycell::msg::SendmeTag,
28
};
29
use tor_error::internal;
30
use zeroize::Zeroizing;
31

            
32
use super::{CryptInit, RelayCellBody};
33
use crate::{client::circuit::CircuitBinding, util::ct};
34

            
35
/// Size of CGO tag, in bytes.
36
const CGO_TAG_LEN: usize = 16;
37
/// Size of CGO payload, in bytes.
38
const CGO_PAYLOAD_LEN: usize = CELL_DATA_LEN - CGO_TAG_LEN;
39

            
40
/// Size of CGO additional data, in bytes.
41
///
42
/// This is used to encode whether the cell command is `RELAY`` or `RELAY_EARLY`.
43
const CGO_AD_LEN: usize = 16;
44

            
45
/// Size of the "H" tweak passed to the UIV+ construction.
46
const HLEN_UIV: usize = CGO_TAG_LEN + CGO_AD_LEN;
47

            
48
/// Block length.
49
/// Used by various types.
50
const BLK_LEN: usize = 16;
51
/// Block length as a typenum; used to parameterize some types
52
/// that use ArrayLen.
53
type BlockLen = typenum::U16;
54
/// A single block.  Used as input to various functions.
55
type Block = [u8; BLK_LEN];
56

            
57
/// Helper trait to define the features we need from a block cipher,
58
/// and make our "where" declarations smaller.
59
///
60
/// Not sealed because it is never used outside of this crate.
61
#[cfg_attr(feature = "bench", visibility::make(pub))]
62
pub(crate) trait BlkCipher:
63
    BlockCipher + KeyInit + BlockSizeUser<BlockSize = BlockLen> + Clone
64
{
65
    /// Length of the key used by this block cipher.
66
    const KEY_LEN: usize;
67
}
68

            
69
/// Helper trait to define the features we need from a block cipher,
70
/// and make our "where" declarations smaller.
71
///
72
/// Not sealed because it is never used outside of this crate.
73
#[cfg_attr(feature = "bench", visibility::make(pub))]
74
pub(crate) trait BlkCipherEnc: BlkCipher + BlockEncrypt {}
75

            
76
/// Helper trait to define the features we need from a block cipher,
77
/// and make our "where" declarations smaller.
78
///
79
/// Not sealed because it is never used outside of this crate.
80
#[cfg_attr(feature = "bench", visibility::make(pub))]
81
pub(crate) trait BlkCipherDec: BlkCipher + BlockDecrypt {}
82

            
83
impl BlkCipher for Aes128 {
84
    const KEY_LEN: usize = 16;
85
}
86
impl BlkCipherEnc for Aes128 {}
87
impl BlkCipherDec for Aes128 {}
88
impl BlkCipher for Aes128Enc {
89
    const KEY_LEN: usize = 16;
90
}
91
impl BlkCipherEnc for Aes128Enc {}
92
impl BlkCipher for Aes128Dec {
93
    const KEY_LEN: usize = 16;
94
}
95
impl BlkCipherDec for Aes128Dec {}
96

            
97
impl BlkCipher for Aes256 {
98
    const KEY_LEN: usize = 32;
99
}
100
impl BlkCipherEnc for Aes256 {}
101
impl BlkCipherDec for Aes256 {}
102
impl BlkCipher for Aes256Enc {
103
    const KEY_LEN: usize = 32;
104
}
105
impl BlkCipherEnc for Aes256Enc {}
106
impl BlkCipher for Aes256Dec {
107
    const KEY_LEN: usize = 32;
108
}
109
impl BlkCipherDec for Aes256Dec {}
110

            
111
/// Define a tweakable block cipher.
112
mod et {
113
    use super::*;
114

            
115
    /// Type of the tweak accepted by the tweakable block cipher.
116
    ///
117
    /// (This might seem like a weird way to express `&[u8; TLEN_ET]`,
118
    /// but it _is_ the way that the UIV construction will provide the tweak.)
119
    pub(super) type EtTweak<'a> = (&'a [u8; CGO_TAG_LEN], u8, &'a [u8; CGO_PAYLOAD_LEN]);
120
    /// Total length of EtTweak fields.
121
    pub(super) const TLEN_ET: usize = CGO_TAG_LEN + 1 + CGO_PAYLOAD_LEN;
122

            
123
    /// Implementation for an LRW2 tweakable block cipher,
124
    /// with block length of [`BLK_LEN`],
125
    /// and specialized tweak of type [`EtTweak`].
126
    ///
127
    /// Corresponds to ET in the specification.
128
    #[derive(Clone)]
129
    pub(super) struct EtCipher<BC: BlkCipher> {
130
        /// Underlying block cipher
131
        kb: BC,
132
        /// Universal hash, initialized with the key KU.
133
        ku: Polyval,
134
    }
135
    impl<BC: BlkCipher> EtCipher<BC> {
136
        /// Helper: Given a tweak, compute the blinding value we will use
137
        /// for encrypting or decryption.
138
1340
        fn compute_tweak_hash(&self, tweak: EtTweak<'_>) -> Zeroizing<Block> {
139
            // We want to compute the UH(KU, tweak.0 | tweak.1 | tweak.2).
140
            // This implementation is optimized to avoid excessive data copying.
141
1340
            let mut ku = self.ku.clone();
142

            
143
1340
            let mut block1 = Zeroizing::new([0_u8; 16]);
144
1340
            block1[0] = tweak.1;
145
1340
            block1[1..16].copy_from_slice(&tweak.2[0..15]);
146
1340
            ku.update(&[(*tweak.0).into(), (*block1).into()]);
147
1340
            ku.update_padded(&tweak.2[15..]);
148
1340
            Zeroizing::new(ku.finalize().into())
149
1340
        }
150
    }
151
    impl<BC: BlkCipherEnc> EtCipher<BC> {
152
        /// Encrypt `block` in-place, using `tweak`.
153
648
        pub(super) fn encrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
154
            // ENC_ET((KB,KU), T, M) = UH(KU,T) ^ ENC_BC(KB, M ^ UH(KU,T))
155
648
            let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
156
648
            xor_into(block, &tag);
157
648
            self.kb.encrypt_block(block.into());
158
648
            xor_into(block, &tag);
159
648
        }
160
    }
161
    impl<BC: BlkCipherDec> EtCipher<BC> {
162
        /// Decrypt `block` in-place, using `tweak`.
163
692
        pub(super) fn decrypt(&self, tweak: EtTweak<'_>, block: &mut Block) {
164
            // DEC_ET((KB,KU), T, M) = UH(KU,T) ^ DEC_BC(KB, M ^ UH(KU,T))
165
692
            let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
166
692
            xor_into(block, &tag);
167
692
            self.kb.decrypt_block(block.into());
168
692
            xor_into(block, &tag);
169
692
        }
170
    }
171
    impl<BC: BlkCipher> CryptInit for EtCipher<BC> {
172
4384
        fn seed_len() -> usize {
173
4384
            BC::key_size() + polyval::KEY_SIZE
174
4384
        }
175
1032
        fn initialize(seed: &[u8]) -> crate::Result<Self> {
176
            // TODO PERF: Here and throughout, these initialize functions do more checking than we
177
            // necessarily need.  We should see if we can simplify them.
178
1032
            if seed.len() != Self::seed_len() {
179
                return Err(internal!("Invalid seed length").into());
180
1032
            }
181
1032
            let (kb, ku) = seed.split_at(BC::key_size());
182
1032
            Ok(Self {
183
1032
                kb: BC::new(kb.into()),
184
1032
                ku: Polyval::new(ku.into()),
185
1032
            })
186
1032
        }
187
    }
188
}
189

            
190
/// Define a tweakable pseudorandom stream generator.
191
mod prf {
192
    use tor_error::internal;
193

            
194
    use super::*;
195

            
196
    /// The type used as a tweak for this PRF.
197
    type PrfTweak = [u8; 16];
198
    /// Length of the PRF's output when used with t=0.
199
    const PRF_N0_LEN: usize = CGO_PAYLOAD_LEN;
200
    /// Offset of the PRF's output when used with t=1.
201
    const PRF_N1_OFFSET: usize = 31 * 16;
202
    const _: () = assert!(PRF_N1_OFFSET >= PRF_N0_LEN);
203

            
204
    /// Pseudorandom function based on CTR128, Polyval, and an underlying block cipher.
205
    //
206
    // Definition: PRF((K, B), T, t) = CTR_{nt}(K, UH(B, T) + (t * C)).
207
    //   where t is 0 or 1 and C is 31.
208
    #[derive(Clone)]
209
    pub(super) struct Prf<BC: BlkCipherEnc> {
210
        /// The underlying block cipher, initialized with the key "K"
211
        k: BC,
212
        /// Thu underlying universal hash, initialized with the key "B"
213
        b: Polyval,
214
    }
215
    impl<BC: BlkCipherEnc> Prf<BC> {
216
        /// Helper: Return a stream cipher, initialized with an IV corresponding
217
        /// to `tweak` and an offset corresponding to `t`.
218
2020
        fn cipher(&self, tweak: &PrfTweak, t: bool) -> ctr::Ctr128BE<BC> {
219
            use {
220
                cipher::{InnerIvInit as _, StreamCipherSeek as _},
221
                ctr::CtrCore,
222
            };
223
2020
            let mut b = self.b.clone(); // TODO PERF: Clone cost here, and below.
224
2020
            b.update(&[(*tweak).into()]);
225
2020
            let mut iv = b.finalize();
226
2020
            *iv.last_mut().expect("no last element?") &= 0xC0; // Clear the low six bits.
227
2020
            let mut cipher: ctr::Ctr128BE<BC> = cipher::StreamCipherCoreWrapper::from_core(
228
2020
                CtrCore::inner_iv_init(self.k.clone(), &iv),
229
            );
230
2020
            if t {
231
700
                debug_assert_eq!(cipher.current_pos::<u32>(), 0_u32);
232
700
                cipher.seek(PRF_N1_OFFSET);
233
1320
            }
234

            
235
2020
            cipher
236
2020
        }
237

            
238
        /// Apply the cipherstream from this Prf to `out`, with tweak parameter `tweak`
239
        /// and offset parameter `t=0`.
240
1320
        pub(super) fn xor_n0_stream(&self, tweak: &PrfTweak, out: &mut [u8; PRF_N0_LEN]) {
241
1320
            let mut stream = self.cipher(tweak, false);
242
1320
            stream.apply_keystream(out);
243
1320
        }
244

            
245
        /// Return a vector containing `n` bytes of this Prf, with tweak
246
        /// parameter `tweak` and offset parameter `t=1`.
247
700
        pub(super) fn get_n1_stream(&self, tweak: &PrfTweak, n: usize) -> Zeroizing<Vec<u8>> {
248
700
            let mut output = Zeroizing::new(vec![0_u8; n]);
249
700
            self.cipher(tweak, true).apply_keystream(output.as_mut());
250
700
            output
251
700
        }
252
    }
253

            
254
    impl<BC: BlkCipherEnc> CryptInit for Prf<BC> {
255
4384
        fn seed_len() -> usize {
256
4384
            BC::key_size() + polyval::KEY_SIZE
257
4384
        }
258
1032
        fn initialize(seed: &[u8]) -> crate::Result<Self> {
259
1032
            if seed.len() != Self::seed_len() {
260
                return Err(internal!("Invalid seed length").into());
261
1032
            }
262
1032
            let (k, b) = seed.split_at(BC::key_size());
263
1032
            Ok(Self {
264
1032
                k: BC::new(k.into()),
265
1032
                b: Polyval::new(b.into()),
266
1032
            })
267
1032
        }
268
    }
269
}
270

            
271
/// Define the UIV+ tweakable wide-block cipher.
272
///
273
/// This construction is a "rugged pseudorandom permutation"; see above.
274
mod uiv {
275
    use super::*;
276

            
277
    /// Type of tweak used as input to the UIV encryption and decryption algorithms.
278
    pub(super) type UivTweak<'a> = (&'a [u8; BLK_LEN], u8);
279

            
280
    /// Keys for a UIV cipher.
281
    #[derive(Clone)]
282
    pub(super) struct Uiv<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
283
        /// Tweakable block cipher key; corresponds to J in the specification.
284
        j: et::EtCipher<EtBC>,
285
        /// PRF keys; corresponds to S in the specification.
286
        s: prf::Prf<PrfBC>,
287

            
288
        /// Testing only: a copy of our current key material.
289
        ///
290
        /// (Used because otherwise, we cannot extract keys from our components,
291
        /// but we _do_ need to test that our key update code works sensibly.)
292
        #[cfg(test)]
293
        pub(super) keys: Zeroizing<Vec<u8>>,
294
    }
295

            
296
    /// Helper: split a mutable cell body into the left-hand (tag) and
297
    /// right-hand (body) parts.
298
1300
    fn split(
299
1300
        cell_body: &mut [u8; CELL_DATA_LEN],
300
1300
    ) -> (&mut [u8; CGO_TAG_LEN], &mut [u8; CGO_PAYLOAD_LEN]) {
301
        //TODO PERF: Make sure that there is no actual checking done here!
302
1300
        let (left, right) = cell_body.split_at_mut(CGO_TAG_LEN);
303
1300
        (
304
1300
            left.try_into().expect("split_at_mut returned wrong size!"),
305
1300
            right.try_into().expect("split_at_mut returned wrong size!"),
306
1300
        )
307
1300
    }
308

            
309
    impl<EtBC: BlkCipherEnc, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
310
        /// Encrypt `cell_body`, using the provided `tweak`.
311
        ///
312
        /// Corresponds to `ENC_UIV.`
313
628
        pub(super) fn encrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
314
            // ENC_UIV((J,S), H, (X_L,X_R)):
315
            //     Y_L <-- ENC_ET(J, (H || X_R), X_L)
316
            //     Y_R <-- X_R ^ PRF_n0(S, Y_L, 0)
317
            //     return (Y_L, Y_R)
318
628
            let (left, right) = split(cell_body);
319
628
            self.j.encrypt((tweak.0, tweak.1, right), left);
320
628
            self.s.xor_n0_stream(left, right);
321
628
        }
322
    }
323
    impl<EtBC: BlkCipherDec, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
324
        /// Decrypt `cell_body`, using the provided `tweak`.
325
        ///
326
        /// Corresponds to `DEC_UIV`.
327
672
        pub(super) fn decrypt(&self, tweak: UivTweak<'_>, cell_body: &mut [u8; CELL_DATA_LEN]) {
328
            // DEC_UIV((J,S), H, (Y_L,Y_R)):
329
            //    X_R <-- Y_R xor PRF_n0(S, Y_L, 0)
330
            //    X_L <-- DEC_ET(J, (H || X_R), Y_L)
331
            //    return (X_L, X_R)
332
672
            let (left, right) = split(cell_body);
333
672
            self.s.xor_n0_stream(left, right);
334
672
            self.j.decrypt((tweak.0, tweak.1, right), left);
335
672
        }
336
    }
337
    impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> Uiv<EtBC, PrfBC> {
338
        /// Modify this Uiv, and the provided nonce, so that its current state
339
        /// cannot be recovered.
340
        ///
341
        /// Corresponds to `UPDATE_UIV`
342
680
        pub(super) fn update(&mut self, nonce: &mut [u8; BLK_LEN]) {
343
            // UPDATE_UIV((J,S), N):
344
            //     ((J',S'), N') = PRF_{n1}(S, N, 1)
345
            //     return ((J', S'), N')
346

            
347
            // TODO PERF: We could allocate significantly less here, by using
348
            // reinitialize functions, and by not actually expanding the key
349
            // stream.
350
680
            let n_bytes = Self::seed_len() + BLK_LEN;
351
680
            let seed = self.s.get_n1_stream(nonce, n_bytes);
352
            #[cfg(test)]
353
680
            {
354
680
                self.keys = Zeroizing::new(seed[..Self::seed_len()].to_vec());
355
680
            }
356
680
            let (j, s, n) = Self::split_seed(&seed);
357
680
            self.j = et::EtCipher::initialize(j).expect("Invalid slice len");
358
680
            self.s = prf::Prf::initialize(s).expect("invalid slice len");
359
680
            nonce[..].copy_from_slice(n);
360
680
        }
361

            
362
        /// Helper: divide seed into J, S, and N.
363
992
        fn split_seed(seed: &[u8]) -> (&[u8], &[u8], &[u8]) {
364
992
            let len_j = et::EtCipher::<EtBC>::seed_len();
365
992
            let len_s = prf::Prf::<PrfBC>::seed_len();
366
992
            (
367
992
                &seed[0..len_j],
368
992
                &seed[len_j..len_j + len_s],
369
992
                &seed[len_j + len_s..],
370
992
            )
371
992
        }
372
    }
373

            
374
    impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for Uiv<EtBC, PrfBC> {
375
2360
        fn seed_len() -> usize {
376
2360
            super::et::EtCipher::<EtBC>::seed_len() + super::prf::Prf::<PrfBC>::seed_len()
377
2360
        }
378
312
        fn initialize(seed: &[u8]) -> crate::Result<Self> {
379
312
            if seed.len() != Self::seed_len() {
380
                return Err(internal!("Invalid seed length").into());
381
312
            }
382
            #[cfg(test)]
383
312
            let keys = Zeroizing::new(seed.to_vec());
384
312
            let (j, s, n) = Self::split_seed(seed);
385
312
            debug_assert!(n.is_empty());
386
            Ok(Self {
387
312
                j: et::EtCipher::initialize(j)?,
388
312
                s: prf::Prf::initialize(s)?,
389
                #[cfg(test)]
390
312
                keys,
391
            })
392
312
        }
393
    }
394
}
395

            
396
/// Xor all bytes from `input` into `output`.
397
2682
fn xor_into<const N: usize>(output: &mut [u8; N], input: &[u8; N]) {
398
45602
    for i in 0..N {
399
42920
        output[i] ^= input[i];
400
42920
    }
401
2682
}
402

            
403
/// Helper: return the first `BLK_LEN` bytes of a slice as an array.
404
///
405
/// TODO PERF: look for other ways to express this, and/or make sure that it
406
/// compiles down to something minimal.
407
#[inline]
408
1236
fn first_block(bytes: &[u8]) -> &[u8; BLK_LEN] {
409
1236
    bytes[0..BLK_LEN].try_into().expect("Slice too short!")
410
1236
}
411

            
412
/// State of a single direction of a CGO layer, at the client or at a relay.
413
#[derive(Clone)]
414
struct CryptState<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
415
    /// The current key "K" for this direction.
416
    uiv: uiv::Uiv<EtBC, PrfBC>,
417
    /// The current nonce value "N" for this direction.
418
    nonce: Zeroizing<[u8; BLK_LEN]>,
419
    /// The current tag value "T'" for this direction.
420
    tag: Zeroizing<[u8; BLK_LEN]>,
421
}
422

            
423
impl<EtBC: BlkCipher, PrfBC: BlkCipherEnc> CryptInit for CryptState<EtBC, PrfBC> {
424
440
    fn seed_len() -> usize {
425
440
        uiv::Uiv::<EtBC, PrfBC>::seed_len() + BLK_LEN
426
440
    }
427
    /// Construct this state from a seed of the appropriate length.
428
248
    fn initialize(seed: &[u8]) -> crate::Result<Self> {
429
248
        if seed.len() != Self::seed_len() {
430
            return Err(internal!("Invalid seed length").into());
431
248
        }
432
248
        let (j_s, n) = seed.split_at(uiv::Uiv::<EtBC, PrfBC>::seed_len());
433
        Ok(Self {
434
248
            uiv: uiv::Uiv::initialize(j_s)?,
435
248
            nonce: Zeroizing::new(n.try_into().expect("invalid splice length")),
436
248
            tag: Zeroizing::new([0; BLK_LEN]),
437
        })
438
248
    }
439
}
440

            
441
/// An instance of CGO used for outbound client encryption.
442
#[cfg_attr(feature = "bench", visibility::make(pub))]
443
#[derive(Clone, derive_more::From)]
444
pub(crate) struct ClientOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
445
where
446
    EtBC: BlkCipherDec,
447
    PrfBC: BlkCipherEnc;
448
impl<EtBC, PrfBC> super::OutboundClientLayer for ClientOutbound<EtBC, PrfBC>
449
where
450
    EtBC: BlkCipherDec,
451
    PrfBC: BlkCipherEnc,
452
{
453
204
    fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
454
204
        cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
455
204
        self.encrypt_outbound(cmd, cell);
456
204
        self.0.uiv.update(&mut self.0.nonce);
457
204
        SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Block length not a valid sendme tag.")
458
204
    }
459
374
    fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
460
        // TODO PERF: consider swap here.
461
374
        let t_new: [u8; BLK_LEN] = *first_block(&*cell.0);
462

            
463
        // Note use of decrypt here: Client operations always use _decrypt_,
464
        // and relay operations always use _encrypt_.
465
374
        self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
466
374
        *self.0.tag = t_new;
467
374
    }
468
}
469

            
470
/// An instance of CGO used for inbound client encryption.
471
#[cfg_attr(feature = "bench", visibility::make(pub))]
472
#[derive(Clone, derive_more::From)]
473
pub(crate) struct ClientInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
474
where
475
    EtBC: BlkCipherDec,
476
    PrfBC: BlkCipherEnc;
477
impl<EtBC, PrfBC> super::InboundClientLayer for ClientInbound<EtBC, PrfBC>
478
where
479
    EtBC: BlkCipherDec,
480
    PrfBC: BlkCipherEnc,
481
{
482
286
    fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
483
286
        let mut t_orig: [u8; BLK_LEN] = *first_block(&*cell.0);
484
        // let t_orig_orig = t_orig;
485

            
486
        // Note use of decrypt here: Client operations always use _decrypt_,
487
        // and relay operations always use _encrypt_.
488
286
        self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
489
286
        *self.0.tag = t_orig;
490
286
        if ct::bytes_eq(&cell.0[..CGO_TAG_LEN], &self.0.nonce[..]) {
491
148
            self.0.uiv.update(&mut t_orig);
492
148
            *self.0.nonce = t_orig;
493
            // assert_eq!(self.0.tag[..BLK_LEN], t_orig_orig[..]);
494
148
            Some((*self.0.tag).into())
495
        } else {
496
138
            None
497
        }
498
286
    }
499
}
500

            
501
/// An instance of CGO used for outbound (away from the client) relay encryption.
502
#[cfg_attr(feature = "bench", visibility::make(pub))]
503
#[derive(Clone, derive_more::From)]
504
pub(crate) struct RelayOutbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
505
where
506
    EtBC: BlkCipherEnc,
507
    PrfBC: BlkCipherEnc;
508
impl<EtBC, PrfBC> super::OutboundRelayLayer for RelayOutbound<EtBC, PrfBC>
509
where
510
    EtBC: BlkCipherEnc,
511
    PrfBC: BlkCipherEnc,
512
{
513
266
    fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag> {
514
266
        let tag = SendmeTag::try_from(&cell.0[0..BLK_LEN]).expect("Invalid sendme length");
515
        // Note use of encrypt here: Client operations always use _decrypt_,
516
        // and relay operations always use _encrypt_.
517
266
        self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
518
266
        *self.0.tag = *first_block(&*cell.0);
519
266
        if ct::bytes_eq(self.0.tag.as_ref(), &self.0.nonce[..]) {
520
148
            self.0.uiv.update(&mut self.0.nonce);
521
148
            Some(tag)
522
        } else {
523
118
            None
524
        }
525
266
    }
526
}
527

            
528
/// An instance of CGO used for inbound (towards the client) relay encryption.
529
#[cfg_attr(feature = "bench", visibility::make(pub))]
530
#[derive(Clone, derive_more::From)]
531
pub(crate) struct RelayInbound<EtBC, PrfBC>(CryptState<EtBC, PrfBC>)
532
where
533
    EtBC: BlkCipherEnc,
534
    PrfBC: BlkCipherEnc;
535
impl<EtBC, PrfBC> super::InboundRelayLayer for RelayInbound<EtBC, PrfBC>
536
where
537
    EtBC: BlkCipherEnc,
538
    PrfBC: BlkCipherEnc,
539
{
540
160
    fn originate(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag {
541
160
        cell.0[0..BLK_LEN].copy_from_slice(&self.0.nonce[..]);
542
160
        self.encrypt_inbound(cmd, cell);
543
160
        self.0.nonce.copy_from_slice(&cell.0[0..BLK_LEN]);
544
160
        self.0.uiv.update(&mut self.0.nonce);
545
        // assert_eq!(self.0.tag[..BLK_LEN], cell.0[0..BLK_LEN]);
546
160
        (*self.0.tag).into()
547
160
    }
548
310
    fn encrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) {
549
        // Note use of encrypt here: Client operations always use _decrypt_,
550
        // and relay operations always use _encrypt_.
551
310
        self.0.uiv.encrypt((&self.0.tag, cmd.into()), &mut cell.0);
552
310
        *self.0.tag = *first_block(&*cell.0);
553
310
    }
554
}
555

            
556
/// A set of cryptographic information as shared by the client and a single relay,
557
/// and
558
#[cfg_attr(feature = "bench", visibility::make(pub))]
559
#[derive(Clone)]
560
pub(crate) struct CryptStatePair<EtBC, PrfBC>
561
where
562
    EtBC: BlkCipher,
563
    PrfBC: BlkCipherEnc,
564
{
565
    /// State for the outbound direction (away from client)
566
    outbound: CryptState<EtBC, PrfBC>,
567
    /// State for the inbound direction (towards client)
568
    inbound: CryptState<EtBC, PrfBC>,
569
    /// Circuit binding information.
570
    binding: CircuitBinding,
571
}
572

            
573
impl<EtBC, PrfBC> CryptInit for CryptStatePair<EtBC, PrfBC>
574
where
575
    EtBC: BlkCipher,
576
    PrfBC: BlkCipherEnc,
577
{
578
128
    fn seed_len() -> usize {
579
128
        CryptState::<EtBC, PrfBC>::seed_len() * 2 + crate::crypto::binding::CIRC_BINDING_LEN
580
128
    }
581
64
    fn initialize(seed: &[u8]) -> crate::Result<Self> {
582
        const {
583
            // can't use assert_eq!() in const
584
            assert!(EtBC::KEY_LEN == PrfBC::KEY_LEN);
585
        }
586
64
        if seed.len() != Self::seed_len() {
587
            return Err(internal!("Invalid seed length").into());
588
64
        }
589
64
        let slen = CryptState::<EtBC, PrfBC>::seed_len();
590
64
        let (outb, inb, binding) = (&seed[0..slen], &seed[slen..slen * 2], &seed[slen * 2..]);
591
        Ok(Self {
592
64
            outbound: CryptState::initialize(outb)?,
593
64
            inbound: CryptState::initialize(inb)?,
594
64
            binding: binding.try_into().expect("Invalid slice length"),
595
        })
596
64
    }
597
}
598

            
599
impl<EtBC, PrfBC> super::ClientLayer<ClientOutbound<EtBC, PrfBC>, ClientInbound<EtBC, PrfBC>>
600
    for CryptStatePair<EtBC, PrfBC>
601
where
602
    EtBC: BlkCipherDec,
603
    PrfBC: BlkCipherEnc,
604
{
605
32
    fn split_client_layer(
606
32
        self,
607
32
    ) -> (
608
32
        ClientOutbound<EtBC, PrfBC>,
609
32
        ClientInbound<EtBC, PrfBC>,
610
32
        CircuitBinding,
611
32
    ) {
612
32
        (self.outbound.into(), self.inbound.into(), self.binding)
613
32
    }
614
}
615

            
616
impl<EtBC, PrfBC> super::RelayLayer<RelayOutbound<EtBC, PrfBC>, RelayInbound<EtBC, PrfBC>>
617
    for CryptStatePair<EtBC, PrfBC>
618
where
619
    EtBC: BlkCipherEnc,
620
    PrfBC: BlkCipherEnc,
621
{
622
32
    fn split_relay_layer(
623
32
        self,
624
32
    ) -> (
625
32
        RelayOutbound<EtBC, PrfBC>,
626
32
        RelayInbound<EtBC, PrfBC>,
627
32
        CircuitBinding,
628
32
    ) {
629
32
        (self.outbound.into(), self.inbound.into(), self.binding)
630
32
    }
631
}
632

            
633
/// Benchmark utilities for the `cgo` module.
634
#[cfg(feature = "bench")]
635
pub mod bench_utils {
636
    pub use super::ClientInbound;
637
    pub use super::ClientOutbound;
638
    pub use super::CryptStatePair;
639
    pub use super::RelayInbound;
640
    pub use super::RelayOutbound;
641

            
642
    /// The throughput for a relay cell in bytes with the CGO scheme.
643
    pub const CGO_THROUGHPUT: u64 = 488;
644
}
645

            
646
#[cfg(test)]
647
mod test {
648
    // @@ begin test lint list maintained by maint/add_warning @@
649
    #![allow(clippy::bool_assert_comparison)]
650
    #![allow(clippy::clone_on_copy)]
651
    #![allow(clippy::dbg_macro)]
652
    #![allow(clippy::mixed_attributes_style)]
653
    #![allow(clippy::print_stderr)]
654
    #![allow(clippy::print_stdout)]
655
    #![allow(clippy::single_char_pattern)]
656
    #![allow(clippy::unwrap_used)]
657
    #![allow(clippy::unchecked_duration_subtraction)]
658
    #![allow(clippy::useless_vec)]
659
    #![allow(clippy::needless_pass_by_value)]
660
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
661

            
662
    use crate::crypto::cell::{
663
        InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
664
    };
665

            
666
    use super::*;
667
    use hex_literal::hex;
668
    use rand::Rng as _;
669
    use tor_basic_utils::test_rng::testing_rng;
670

            
671
    #[test]
672
    fn testvec_xor() {
673
        let mut b: [u8; 20] = *b"turning and turning ";
674
        let s = b"in the widening gyre";
675
        xor_into(&mut b, s);
676
        assert_eq!(b[..], hex!("1d1b521a010b4757080a014e1d1b154e0e171545"));
677
    }
678

            
679
    #[test]
680
    fn testvec_polyval() {
681
        use polyval::Polyval;
682
        use polyval::universal_hash::{KeyInit, UniversalHash};
683

            
684
        // Test vectors from RFC8452 worked example in appendix A.
685
        let h = hex!("25629347589242761d31f826ba4b757b");
686
        let x_1 = hex!("4f4f95668c83dfb6401762bb2d01a262");
687
        let x_2 = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
688

            
689
        let mut hash = Polyval::new(&h.into());
690
        hash.update(&[x_1.into(), x_2.into()]);
691
        let result: [u8; 16] = hash.finalize().into();
692
        assert_eq!(result, hex!("f7a3b47b846119fae5b7866cf5e5b77e"));
693
    }
694

            
695
    // These True/False constants are here to make our test data parse without changes.
696
    #[allow(non_upper_case_globals)]
697
    const False: bool = false;
698
    #[allow(non_upper_case_globals)]
699
    const True: bool = true;
700
    include!("../../../testdata/cgo_et.rs");
701
    include!("../../../testdata/cgo_prf.rs");
702
    include!("../../../testdata/cgo_uiv.rs");
703
    include!("../../../testdata/cgo_relay.rs");
704
    include!("../../../testdata/cgo_client.rs");
705

            
706
    /// Decode s as a N-byte hex string, or panic.
707
    fn unhex<const N: usize>(s: &str) -> [u8; N] {
708
        hex::decode(s).unwrap().try_into().unwrap()
709
    }
710

            
711
    #[test]
712
    fn testvec_et() {
713
        for (encrypt, keys, tweak, input, expect_output) in ET_TEST_VECTORS {
714
            let keys: [u8; 32] = unhex(keys);
715
            let tweak: [u8; et::TLEN_ET] = unhex(tweak);
716
            let mut block: [u8; 16] = unhex(input);
717
            let expect_output: [u8; 16] = unhex(expect_output);
718
            let et: et::EtCipher<Aes128> = et::EtCipher::initialize(&keys).unwrap();
719
            let tweak = (
720
                tweak[0..16].try_into().unwrap(),
721
                tweak[16],
722
                &tweak[17..].try_into().unwrap(),
723
            );
724
            if *encrypt {
725
                et.encrypt(tweak, &mut block);
726
            } else {
727
                et.decrypt(tweak, &mut block);
728
            }
729
            assert_eq!(block, expect_output);
730
        }
731
    }
732

            
733
    #[test]
734
    fn testvec_prf() {
735
        for (keys, offset, tweak, expect_output) in PRF_TEST_VECTORS {
736
            let keys: [u8; 32] = unhex(keys);
737
            assert!([0, 1].contains(offset));
738
            let tweak: [u8; 16] = unhex(tweak);
739
            let expect_output = hex::decode(expect_output).unwrap();
740
            let prf: prf::Prf<Aes128> = prf::Prf::initialize(&keys).unwrap();
741
            if *offset == 0 {
742
                assert_eq!(expect_output.len(), CGO_PAYLOAD_LEN);
743
                let mut data = [0_u8; CGO_PAYLOAD_LEN];
744
                prf.xor_n0_stream(&tweak, &mut data);
745
                assert_eq!(expect_output[..], data[..]);
746
            } else {
747
                let data = prf.get_n1_stream(&tweak, expect_output.len());
748
                assert_eq!(expect_output[..], data[..]);
749
            }
750
        }
751
    }
752

            
753
    #[test]
754
    fn testvec_uiv() {
755
        for (encrypt, keys, tweak, left, right, (expect_left, expect_right)) in UIV_TEST_VECTORS {
756
            let keys: [u8; 64] = unhex(keys);
757
            let tweak: [u8; 17] = unhex(tweak);
758
            let mut cell: [u8; 509] = unhex(&format!("{left}{right}"));
759
            let expected: [u8; 509] = unhex(&format!("{expect_left}{expect_right}"));
760

            
761
            let uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
762
            let htweak = (tweak[0..16].try_into().unwrap(), tweak[16]);
763
            if *encrypt {
764
                uiv.encrypt(htweak, &mut cell);
765
            } else {
766
                uiv.decrypt(htweak, &mut cell);
767
            }
768
            assert_eq!(cell, expected);
769
        }
770
    }
771

            
772
    #[test]
773
    fn testvec_uiv_update() {
774
        let mut rng = testing_rng();
775

            
776
        for (keys, nonce, (expect_keys, expect_nonce)) in UIV_UPDATE_TEST_VECTORS {
777
            let keys: [u8; 64] = unhex(keys);
778
            let mut nonce: [u8; 16] = unhex(nonce);
779
            let mut uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
780
            let expect_keys: [u8; 64] = unhex(expect_keys);
781
            let expect_nonce: [u8; 16] = unhex(expect_nonce);
782
            uiv.update(&mut nonce);
783
            assert_eq!(&nonce, &expect_nonce);
784
            assert_eq!(&uiv.keys[..], &expect_keys[..]);
785

            
786
            // Make sure that we can get the same results when we initialize a new UIV with the keys
787
            // allegedly used to reinitialize this one.
788
            let uiv2: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&uiv.keys[..]).unwrap();
789

            
790
            let tweak: [u8; 16] = rng.random();
791
            let cmd = rng.random();
792
            let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
793
            let mut msg2 = msg1.clone();
794

            
795
            uiv.encrypt((&tweak, cmd), &mut msg1);
796
            uiv2.encrypt((&tweak, cmd), &mut msg2);
797
        }
798
    }
799

            
800
    #[test]
801
    fn testvec_cgo_relay() {
802
        for (inbound, (k, n, tprime), ad, t, c, output) in CGO_RELAY_TEST_VECTORS {
803
            let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
804
            let tprime: [u8; 16] = unhex(tprime);
805
            let ad: [u8; 1] = unhex(ad);
806
            let msg: [u8; CELL_DATA_LEN] = unhex(&format!("{t}{c}"));
807
            let mut msg = RelayCellBody(Box::new(msg));
808

            
809
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
810
            *state.tag = tprime;
811
            let state = if *inbound {
812
                let mut s = RelayInbound::from(state);
813
                s.encrypt_inbound(ad[0].into(), &mut msg);
814
                s.0
815
            } else {
816
                let mut s = RelayOutbound::from(state);
817
                s.decrypt_outbound(ad[0].into(), &mut msg);
818
                s.0
819
            };
820

            
821
            // expected values
822
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
823
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
824
            let ex_k: [u8; 64] = unhex(ex_k);
825
            let ex_n: [u8; 16] = unhex(ex_n);
826
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
827
            assert_eq!(&ex_msg[..], &msg.0[..]);
828
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
829
            assert_eq!(&state.nonce[..], &ex_n[..]);
830
            assert_eq!(&state.tag[..], &ex_tprime[..]);
831
        }
832
    }
833

            
834
    #[test]
835
    fn testvec_cgo_relay_originate() {
836
        for ((k, n, tprime), ad, m, output) in CGO_RELAY_ORIGINATE_TEST_VECTORS {
837
            let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
838
            let tprime: [u8; 16] = unhex(tprime);
839
            let ad: [u8; 1] = unhex(ad);
840
            let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
841
            let mut msg = [0_u8; CELL_DATA_LEN];
842
            msg[16..].copy_from_slice(&msg_body[..]);
843
            let mut msg = RelayCellBody(Box::new(msg));
844

            
845
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
846
            *state.tag = tprime;
847
            let mut state = RelayInbound::from(state);
848
            state.originate(ad[0].into(), &mut msg);
849
            let state = state.0;
850

            
851
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
852
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
853
            let ex_k: [u8; 64] = unhex(ex_k);
854
            let ex_n: [u8; 16] = unhex(ex_n);
855
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
856
            assert_eq!(&ex_msg[..], &msg.0[..]);
857
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
858
            assert_eq!(&state.nonce[..], &ex_n[..]);
859
            assert_eq!(&state.tag[..], &ex_tprime[..]);
860
        }
861
    }
862

            
863
    #[test]
864
    fn testvec_cgo_client_originate() {
865
        for (ss, hop, ad, m, output) in CGO_CLIENT_ORIGINATE_TEST_VECTORS {
866
            assert!(*hop > 0); // the test vectors are 1-indexed.
867
            let mut client = OutboundClientCrypt::new();
868
            let mut individual_layers = Vec::new();
869
            for (k, n, tprime) in ss {
870
                let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
871
                let tprime: [u8; 16] = unhex(tprime);
872
                let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
873
                *state.tag = tprime;
874
                client.add_layer(Box::new(ClientOutbound::from(state.clone())));
875
                individual_layers.push(ClientOutbound::from(state));
876
            }
877

            
878
            let ad: [u8; 1] = unhex(ad);
879
            let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
880
            let mut msg = [0_u8; CELL_DATA_LEN];
881
            msg[16..].copy_from_slice(&msg_body[..]);
882
            let mut msg = RelayCellBody(Box::new(msg));
883
            let mut msg2 = msg.clone();
884

            
885
            // Encrypt using the OutboundClientCrypt object...
886
            client
887
                .encrypt(ad[0].into(), &mut msg, (*hop - 1).into())
888
                .unwrap();
889
            // And a second time manually, using individual_layers.
890
            //
891
            // (We do this so we can actually inspect that their internal state matches the test vectors.)
892
            {
893
                let hop_idx = usize::from(*hop) - 1;
894
                individual_layers[hop_idx].originate_for(ad[0].into(), &mut msg2);
895
                for idx in (0..hop_idx).rev() {
896
                    individual_layers[idx].encrypt_outbound(ad[0].into(), &mut msg2);
897
                }
898
            }
899
            assert_eq!(&msg.0[..], &msg2.0[..]);
900

            
901
            let (ex_ss, (ex_t, ex_c)) = output;
902
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
903
            assert_eq!(&ex_msg[..], &msg.0[..]);
904

            
905
            for (layer, (ex_k, ex_n, ex_tprime)) in individual_layers.iter().zip(ex_ss.iter()) {
906
                let state = &layer.0;
907
                let ex_k: [u8; 64] = unhex(ex_k);
908
                let ex_n: [u8; 16] = unhex(ex_n);
909
                let ex_tprime: [u8; 16] = unhex(ex_tprime);
910

            
911
                assert_eq!(&state.uiv.keys[..], &ex_k[..]);
912
                assert_eq!(&state.nonce[..], &ex_n[..]);
913
                assert_eq!(&state.tag[..], &ex_tprime);
914
            }
915
        }
916
    }
917
}