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
1336
        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
1336
            let mut ku = self.ku.clone();
142

            
143
1336
            let mut block1 = Zeroizing::new([0_u8; 16]);
144
1336
            block1[0] = tweak.1;
145
1336
            block1[1..16].copy_from_slice(&tweak.2[0..15]);
146
1336
            ku.update(&[(*tweak.0).into(), (*block1).into()]);
147
1336
            ku.update_padded(&tweak.2[15..]);
148
1336
            Zeroizing::new(ku.finalize().into())
149
1336
        }
150
    }
151
    impl<BC: BlkCipherEnc> EtCipher<BC> {
152
        /// Encrypt `block` in-place, using `tweak`.
153
646
        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
646
            let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
156
646
            xor_into(block, &tag);
157
646
            self.kb.encrypt_block(block.into());
158
646
            xor_into(block, &tag);
159
646
        }
160
    }
161
    impl<BC: BlkCipherDec> EtCipher<BC> {
162
        /// Decrypt `block` in-place, using `tweak`.
163
690
        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
690
            let tag: Zeroizing<[u8; 16]> = self.compute_tweak_hash(tweak);
166
690
            xor_into(block, &tag);
167
690
            self.kb.decrypt_block(block.into());
168
690
            xor_into(block, &tag);
169
690
        }
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
            let ku: &[u8; 16] = ku
183
1032
                .try_into()
184
1032
                .expect("Incorrect key size, even though it was validated!?");
185
1032
            Ok(Self {
186
1032
                kb: BC::new(kb.into()),
187
1032
                ku: Polyval::new(ku.into()),
188
1032
            })
189
1032
        }
190
    }
191
}
192

            
193
/// Define a tweakable pseudorandom stream generator.
194
mod prf {
195
    use tor_error::internal;
196

            
197
    use super::*;
198

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

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

            
239
2016
            cipher
240
2016
        }
241

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

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

            
258
    impl<BC: BlkCipherEnc> CryptInit for Prf<BC> {
259
4384
        fn seed_len() -> usize {
260
4384
            BC::key_size() + polyval::KEY_SIZE
261
4384
        }
262
1032
        fn initialize(seed: &[u8]) -> crate::Result<Self> {
263
1032
            if seed.len() != Self::seed_len() {
264
                return Err(internal!("Invalid seed length").into());
265
1032
            }
266
1032
            let (k, b) = seed.split_at(BC::key_size());
267
1032
            let b: &[u8; 16] = b
268
1032
                .try_into()
269
1032
                .expect("Incorrect key size, even though it was validated!?");
270
1032
            Ok(Self {
271
1032
                k: BC::new(k.into()),
272
1032
                b: Polyval::new(b.into()),
273
1032
            })
274
1032
        }
275
    }
276
}
277

            
278
/// Define the UIV+ tweakable wide-block cipher.
279
///
280
/// This construction is a "rugged pseudorandom permutation"; see above.
281
mod uiv {
282
    use super::*;
283

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

            
287
    /// Keys for a UIV cipher.
288
    #[derive(Clone)]
289
    pub(super) struct Uiv<EtBC: BlkCipher, PrfBC: BlkCipherEnc> {
290
        /// Tweakable block cipher key; corresponds to J in the specification.
291
        j: et::EtCipher<EtBC>,
292
        /// PRF keys; corresponds to S in the specification.
293
        s: prf::Prf<PrfBC>,
294

            
295
        /// Testing only: a copy of our current key material.
296
        ///
297
        /// (Used because otherwise, we cannot extract keys from our components,
298
        /// but we _do_ need to test that our key update code works sensibly.)
299
        #[cfg(test)]
300
        pub(super) keys: Zeroizing<Vec<u8>>,
301
    }
302

            
303
    /// Helper: split a mutable cell body into the left-hand (tag) and
304
    /// right-hand (body) parts.
305
1296
    fn split(
306
1296
        cell_body: &mut [u8; CELL_DATA_LEN],
307
1296
    ) -> (&mut [u8; CGO_TAG_LEN], &mut [u8; CGO_PAYLOAD_LEN]) {
308
        //TODO PERF: Make sure that there is no actual checking done here!
309
1296
        let (left, right) = cell_body.split_at_mut(CGO_TAG_LEN);
310
1296
        (
311
1296
            left.try_into().expect("split_at_mut returned wrong size!"),
312
1296
            right.try_into().expect("split_at_mut returned wrong size!"),
313
1296
        )
314
1296
    }
315

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

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

            
369
        /// Helper: divide seed into J, S, and N.
370
992
        fn split_seed(seed: &[u8]) -> (&[u8], &[u8], &[u8]) {
371
992
            let len_j = et::EtCipher::<EtBC>::seed_len();
372
992
            let len_s = prf::Prf::<PrfBC>::seed_len();
373
992
            (
374
992
                &seed[0..len_j],
375
992
                &seed[len_j..len_j + len_s],
376
992
                &seed[len_j + len_s..],
377
992
            )
378
992
        }
379
    }
380

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

            
403
/// Xor all bytes from `input` into `output`.
404
2674
fn xor_into<const N: usize>(output: &mut [u8; N], input: &[u8; N]) {
405
45466
    for i in 0..N {
406
42792
        output[i] ^= input[i];
407
42792
    }
408
2674
}
409

            
410
/// Helper: return the first `BLK_LEN` bytes of a slice as an array.
411
///
412
/// TODO PERF: look for other ways to express this, and/or make sure that it
413
/// compiles down to something minimal.
414
#[inline]
415
1232
fn first_block(bytes: &[u8]) -> &[u8; BLK_LEN] {
416
1232
    bytes[0..BLK_LEN].try_into().expect("Slice too short!")
417
1232
}
418

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

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

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

            
470
        // Note use of decrypt here: Client operations always use _decrypt_,
471
        // and relay operations always use _encrypt_.
472
388
        self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
473
388
        *self.0.tag = t_new;
474
388
    }
475
}
476

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

            
493
        // Note use of decrypt here: Client operations always use _decrypt_,
494
        // and relay operations always use _encrypt_.
495
270
        self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
496
270
        *self.0.tag = t_orig;
497
270
        if ct::bytes_eq(&cell.0[..CGO_TAG_LEN], &self.0.nonce[..]) {
498
148
            self.0.uiv.update(&mut t_orig);
499
148
            *self.0.nonce = t_orig;
500
            // assert_eq!(self.0.tag[..BLK_LEN], t_orig_orig[..]);
501
148
            Some((*self.0.tag).into())
502
        } else {
503
122
            None
504
        }
505
270
    }
506
}
507

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

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

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

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

            
606
impl<EtBC, PrfBC> super::ClientLayer<ClientOutbound<EtBC, PrfBC>, ClientInbound<EtBC, PrfBC>>
607
    for CryptStatePair<EtBC, PrfBC>
608
where
609
    EtBC: BlkCipherDec,
610
    PrfBC: BlkCipherEnc,
611
{
612
32
    fn split_client_layer(
613
32
        self,
614
32
    ) -> (
615
32
        ClientOutbound<EtBC, PrfBC>,
616
32
        ClientInbound<EtBC, PrfBC>,
617
32
        CircuitBinding,
618
32
    ) {
619
32
        (self.outbound.into(), self.inbound.into(), self.binding)
620
32
    }
621
}
622

            
623
impl<EtBC, PrfBC> super::RelayLayer<RelayOutbound<EtBC, PrfBC>, RelayInbound<EtBC, PrfBC>>
624
    for CryptStatePair<EtBC, PrfBC>
625
where
626
    EtBC: BlkCipherEnc,
627
    PrfBC: BlkCipherEnc,
628
{
629
32
    fn split_relay_layer(
630
32
        self,
631
32
    ) -> (
632
32
        RelayOutbound<EtBC, PrfBC>,
633
32
        RelayInbound<EtBC, PrfBC>,
634
32
        CircuitBinding,
635
32
    ) {
636
32
        (self.outbound.into(), self.inbound.into(), self.binding)
637
32
    }
638
}
639

            
640
/// Benchmark utilities for the `cgo` module.
641
#[cfg(feature = "bench")]
642
pub mod bench_utils {
643
    pub use super::ClientInbound;
644
    pub use super::ClientOutbound;
645
    pub use super::CryptStatePair;
646
    pub use super::RelayInbound;
647
    pub use super::RelayOutbound;
648

            
649
    /// The throughput for a relay cell in bytes with the CGO scheme.
650
    pub const CGO_THROUGHPUT: u64 = 488;
651
}
652

            
653
#[cfg(test)]
654
mod test {
655
    // @@ begin test lint list maintained by maint/add_warning @@
656
    #![allow(clippy::bool_assert_comparison)]
657
    #![allow(clippy::clone_on_copy)]
658
    #![allow(clippy::dbg_macro)]
659
    #![allow(clippy::mixed_attributes_style)]
660
    #![allow(clippy::print_stderr)]
661
    #![allow(clippy::print_stdout)]
662
    #![allow(clippy::single_char_pattern)]
663
    #![allow(clippy::unwrap_used)]
664
    #![allow(clippy::unchecked_time_subtraction)]
665
    #![allow(clippy::useless_vec)]
666
    #![allow(clippy::needless_pass_by_value)]
667
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
668

            
669
    use crate::crypto::cell::{
670
        InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
671
    };
672

            
673
    use super::*;
674
    use hex_literal::hex;
675
    use rand::Rng as _;
676
    use tor_basic_utils::test_rng::testing_rng;
677

            
678
    #[test]
679
    fn testvec_xor() {
680
        let mut b: [u8; 20] = *b"turning and turning ";
681
        let s = b"in the widening gyre";
682
        xor_into(&mut b, s);
683
        assert_eq!(b[..], hex!("1d1b521a010b4757080a014e1d1b154e0e171545"));
684
    }
685

            
686
    #[test]
687
    fn testvec_polyval() {
688
        use polyval::Polyval;
689
        use polyval::universal_hash::UniversalHash;
690

            
691
        // Test vectors from RFC8452 worked example in appendix A.
692
        let h = hex!("25629347589242761d31f826ba4b757b");
693
        let x_1 = hex!("4f4f95668c83dfb6401762bb2d01a262");
694
        let x_2 = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
695

            
696
        let mut hash = Polyval::new(&h.into());
697
        hash.update(&[x_1.into(), x_2.into()]);
698
        let result: [u8; 16] = hash.finalize().into();
699
        assert_eq!(result, hex!("f7a3b47b846119fae5b7866cf5e5b77e"));
700
    }
701

            
702
    // These True/False constants are here to make our test data parse without changes.
703
    #[allow(non_upper_case_globals)]
704
    const False: bool = false;
705
    #[allow(non_upper_case_globals)]
706
    const True: bool = true;
707
    include!("../../../testdata/cgo_et.rs");
708
    include!("../../../testdata/cgo_prf.rs");
709
    include!("../../../testdata/cgo_uiv.rs");
710
    include!("../../../testdata/cgo_relay.rs");
711
    include!("../../../testdata/cgo_client.rs");
712

            
713
    /// Decode s as a N-byte hex string, or panic.
714
    fn unhex<const N: usize>(s: &str) -> [u8; N] {
715
        hex::decode(s).unwrap().try_into().unwrap()
716
    }
717

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

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

            
760
    #[test]
761
    fn testvec_uiv() {
762
        for (encrypt, keys, tweak, left, right, (expect_left, expect_right)) in UIV_TEST_VECTORS {
763
            let keys: [u8; 64] = unhex(keys);
764
            let tweak: [u8; 17] = unhex(tweak);
765
            let mut cell: [u8; 509] = unhex(&format!("{left}{right}"));
766
            let expected: [u8; 509] = unhex(&format!("{expect_left}{expect_right}"));
767

            
768
            let uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
769
            let htweak = (tweak[0..16].try_into().unwrap(), tweak[16]);
770
            if *encrypt {
771
                uiv.encrypt(htweak, &mut cell);
772
            } else {
773
                uiv.decrypt(htweak, &mut cell);
774
            }
775
            assert_eq!(cell, expected);
776
        }
777
    }
778

            
779
    #[test]
780
    fn testvec_uiv_update() {
781
        let mut rng = testing_rng();
782

            
783
        for (keys, nonce, (expect_keys, expect_nonce)) in UIV_UPDATE_TEST_VECTORS {
784
            let keys: [u8; 64] = unhex(keys);
785
            let mut nonce: [u8; 16] = unhex(nonce);
786
            let mut uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
787
            let expect_keys: [u8; 64] = unhex(expect_keys);
788
            let expect_nonce: [u8; 16] = unhex(expect_nonce);
789
            uiv.update(&mut nonce);
790
            assert_eq!(&nonce, &expect_nonce);
791
            assert_eq!(&uiv.keys[..], &expect_keys[..]);
792

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

            
797
            let tweak: [u8; 16] = rng.random();
798
            let cmd = rng.random();
799
            let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
800
            let mut msg2 = msg1.clone();
801

            
802
            uiv.encrypt((&tweak, cmd), &mut msg1);
803
            uiv2.encrypt((&tweak, cmd), &mut msg2);
804
        }
805
    }
806

            
807
    #[test]
808
    fn testvec_cgo_relay() {
809
        for (inbound, (k, n, tprime), ad, t, c, output) in CGO_RELAY_TEST_VECTORS {
810
            let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
811
            let tprime: [u8; 16] = unhex(tprime);
812
            let ad: [u8; 1] = unhex(ad);
813
            let msg: [u8; CELL_DATA_LEN] = unhex(&format!("{t}{c}"));
814
            let mut msg = RelayCellBody(Box::new(msg));
815

            
816
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
817
            *state.tag = tprime;
818
            let state = if *inbound {
819
                let mut s = RelayInbound::from(state);
820
                s.encrypt_inbound(ad[0].into(), &mut msg);
821
                s.0
822
            } else {
823
                let mut s = RelayOutbound::from(state);
824
                s.decrypt_outbound(ad[0].into(), &mut msg);
825
                s.0
826
            };
827

            
828
            // expected values
829
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
830
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
831
            let ex_k: [u8; 64] = unhex(ex_k);
832
            let ex_n: [u8; 16] = unhex(ex_n);
833
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
834
            assert_eq!(&ex_msg[..], &msg.0[..]);
835
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
836
            assert_eq!(&state.nonce[..], &ex_n[..]);
837
            assert_eq!(&state.tag[..], &ex_tprime[..]);
838
        }
839
    }
840

            
841
    #[test]
842
    fn testvec_cgo_relay_originate() {
843
        for ((k, n, tprime), ad, m, output) in CGO_RELAY_ORIGINATE_TEST_VECTORS {
844
            let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
845
            let tprime: [u8; 16] = unhex(tprime);
846
            let ad: [u8; 1] = unhex(ad);
847
            let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
848
            let mut msg = [0_u8; CELL_DATA_LEN];
849
            msg[16..].copy_from_slice(&msg_body[..]);
850
            let mut msg = RelayCellBody(Box::new(msg));
851

            
852
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
853
            *state.tag = tprime;
854
            let mut state = RelayInbound::from(state);
855
            state.originate(ad[0].into(), &mut msg);
856
            let state = state.0;
857

            
858
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
859
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
860
            let ex_k: [u8; 64] = unhex(ex_k);
861
            let ex_n: [u8; 16] = unhex(ex_n);
862
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
863
            assert_eq!(&ex_msg[..], &msg.0[..]);
864
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
865
            assert_eq!(&state.nonce[..], &ex_n[..]);
866
            assert_eq!(&state.tag[..], &ex_tprime[..]);
867
        }
868
    }
869

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

            
885
            let ad: [u8; 1] = unhex(ad);
886
            let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
887
            let mut msg = [0_u8; CELL_DATA_LEN];
888
            msg[16..].copy_from_slice(&msg_body[..]);
889
            let mut msg = RelayCellBody(Box::new(msg));
890
            let mut msg2 = msg.clone();
891

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

            
908
            let (ex_ss, (ex_t, ex_c)) = output;
909
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
910
            assert_eq!(&ex_msg[..], &msg.0[..]);
911

            
912
            for (layer, (ex_k, ex_n, ex_tprime)) in individual_layers.iter().zip(ex_ss.iter()) {
913
                let state = &layer.0;
914
                let ex_k: [u8; 64] = unhex(ex_k);
915
                let ex_n: [u8; 16] = unhex(ex_n);
916
                let ex_tprime: [u8; 16] = unhex(ex_tprime);
917

            
918
                assert_eq!(&state.uiv.keys[..], &ex_k[..]);
919
                assert_eq!(&state.nonce[..], &ex_n[..]);
920
                assert_eq!(&state.tag[..], &ex_tprime);
921
            }
922
        }
923
    }
924
}