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::{universal_hash::UniversalHash, Polyval};
25
use static_assertions::const_assert;
26
use tor_cell::{
27
    chancell::{ChanCmd, CELL_DATA_LEN},
28
    relaycell::msg::SendmeTag,
29
};
30
use tor_error::internal;
31
use zeroize::Zeroizing;
32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
195
    use super::*;
196

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

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

            
236
2072
            cipher
237
2072
        }
238

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
665
    use crate::crypto::cell::{
666
        InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
667
    };
668

            
669
    use super::*;
670
    use hex_literal::hex;
671
    use rand::Rng as _;
672
    use tor_basic_utils::test_rng::testing_rng;
673

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

            
682
    #[test]
683
    fn testvec_polyval() {
684
        use polyval::universal_hash::{KeyInit, UniversalHash};
685
        use polyval::Polyval;
686

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

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

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

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

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

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

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

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

            
775
    #[test]
776
    fn testvec_uiv_update() {
777
        let mut rng = testing_rng();
778

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

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

            
793
            let tweak: [u8; 16] = rng.random();
794
            let cmd = rng.random();
795
            let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
796
            let mut msg2 = msg1.clone();
797

            
798
            uiv.encrypt((&tweak, cmd), &mut msg1);
799
            uiv2.encrypt((&tweak, cmd), &mut msg2);
800
        }
801
    }
802

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

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

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

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

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

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

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

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

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

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

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

            
914
                assert_eq!(&state.uiv.keys[..], &ex_k[..]);
915
                assert_eq!(&state.nonce[..], &ex_n[..]);
916
                assert_eq!(&state.tag[..], &ex_tprime);
917
            }
918
        }
919
    }
920
}