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::common::array::Array;
23
use cipher::{BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, KeyInit, StreamCipher as _};
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: KeyInit + BlockSizeUser<BlockSize = BlockLen> + Clone {
63
    /// Length of the key used by this block cipher.
64
    const KEY_LEN: usize;
65
}
66

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

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

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

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

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

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

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

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

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

            
198
    use super::*;
199

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

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

            
240
2072
            cipher
241
2072
        }
242

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

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

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

            
272
1032
            let b: &[u8; 16] = b
273
1032
                .try_into()
274
1032
                .expect("Incorrect key size, even though it was validated!?");
275
1032
            Ok(Self {
276
1032
                k: BC::new(k),
277
1032
                b: Polyval::new(b.into()),
278
1032
            })
279
1032
        }
280
    }
281
}
282

            
283
/// Define the UIV+ tweakable wide-block cipher.
284
///
285
/// This construction is a "rugged pseudorandom permutation"; see above.
286
mod uiv {
287
    use super::*;
288

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

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

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

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

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

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

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

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

            
408
/// Xor all bytes from `input` into `output`.
409
2786
fn xor_into<const N: usize>(output: &mut [u8; N], input: &[u8; N]) {
410
44584
    for i in 0..N {
411
44584
        output[i] ^= input[i];
412
44584
    }
413
2786
}
414

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

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

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

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

            
475
        // Note use of decrypt here: Client operations always use _decrypt_,
476
        // and relay operations always use _encrypt_.
477
410
        self.0.uiv.decrypt((&self.0.tag, cmd.into()), &mut cell.0);
478
410
        *self.0.tag = t_new;
479
410
    }
480
}
481

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

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

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

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

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

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

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

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

            
645
/// Benchmark utilities for the `cgo` module.
646
#[cfg(feature = "bench")]
647
pub mod bench_utils {
648
    pub use super::ClientInbound;
649
    pub use super::ClientOutbound;
650
    pub use super::CryptStatePair;
651
    pub use super::RelayInbound;
652
    pub use super::RelayOutbound;
653

            
654
    /// The throughput for a relay cell in bytes with the CGO scheme.
655
    pub const CGO_THROUGHPUT: u64 = 488;
656
}
657

            
658
#[cfg(test)]
659
mod test {
660
    // @@ begin test lint list maintained by maint/add_warning @@
661
    #![allow(clippy::bool_assert_comparison)]
662
    #![allow(clippy::clone_on_copy)]
663
    #![allow(clippy::dbg_macro)]
664
    #![allow(clippy::mixed_attributes_style)]
665
    #![allow(clippy::print_stderr)]
666
    #![allow(clippy::print_stdout)]
667
    #![allow(clippy::single_char_pattern)]
668
    #![allow(clippy::unwrap_used)]
669
    #![allow(clippy::unchecked_time_subtraction)]
670
    #![allow(clippy::useless_vec)]
671
    #![allow(clippy::needless_pass_by_value)]
672
    #![allow(clippy::string_slice)] // See arti#2571
673
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
674

            
675
    use crate::crypto::cell::{
676
        InboundRelayLayer, OutboundClientCrypt, OutboundClientLayer, OutboundRelayLayer,
677
    };
678

            
679
    use super::*;
680
    use hex_literal::hex;
681
    use rand::RngExt as _;
682
    use tor_basic_utils::test_rng::testing_rng;
683

            
684
    #[test]
685
    fn testvec_xor() {
686
        let mut b: [u8; 20] = *b"turning and turning ";
687
        let s = b"in the widening gyre";
688
        xor_into(&mut b, s);
689
        assert_eq!(b[..], hex!("1d1b521a010b4757080a014e1d1b154e0e171545"));
690
    }
691

            
692
    #[test]
693
    fn testvec_polyval() {
694
        use polyval::Polyval;
695
        use polyval::universal_hash::UniversalHash;
696

            
697
        // Test vectors from RFC8452 worked example in appendix A.
698
        let h = hex!("25629347589242761d31f826ba4b757b");
699
        let x_1 = hex!("4f4f95668c83dfb6401762bb2d01a262");
700
        let x_2 = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
701

            
702
        let mut hash = Polyval::new(&h.into());
703
        hash.update(&[x_1.into(), x_2.into()]);
704
        let result: [u8; 16] = hash.finalize().into();
705
        assert_eq!(result, hex!("f7a3b47b846119fae5b7866cf5e5b77e"));
706
    }
707

            
708
    // These True/False constants are here to make our test data parse without changes.
709
    #[allow(non_upper_case_globals)]
710
    const False: bool = false;
711
    #[allow(non_upper_case_globals)]
712
    const True: bool = true;
713
    include!("../../../testdata/cgo_et.rs");
714
    include!("../../../testdata/cgo_prf.rs");
715
    include!("../../../testdata/cgo_uiv.rs");
716
    include!("../../../testdata/cgo_relay.rs");
717
    include!("../../../testdata/cgo_client.rs");
718

            
719
    /// Decode s as a N-byte hex string, or panic.
720
    fn unhex<const N: usize>(s: &str) -> [u8; N] {
721
        hex::decode(s).unwrap().try_into().unwrap()
722
    }
723

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

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

            
766
    #[test]
767
    fn testvec_uiv() {
768
        for (encrypt, keys, tweak, left, right, (expect_left, expect_right)) in UIV_TEST_VECTORS {
769
            let keys: [u8; 64] = unhex(keys);
770
            let tweak: [u8; 17] = unhex(tweak);
771
            let mut cell: [u8; 509] = unhex(&format!("{left}{right}"));
772
            let expected: [u8; 509] = unhex(&format!("{expect_left}{expect_right}"));
773

            
774
            let uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
775
            let htweak = (tweak[0..16].try_into().unwrap(), tweak[16]);
776
            if *encrypt {
777
                uiv.encrypt(htweak, &mut cell);
778
            } else {
779
                uiv.decrypt(htweak, &mut cell);
780
            }
781
            assert_eq!(cell, expected);
782
        }
783
    }
784

            
785
    #[test]
786
    fn testvec_uiv_update() {
787
        let mut rng = testing_rng();
788

            
789
        for (keys, nonce, (expect_keys, expect_nonce)) in UIV_UPDATE_TEST_VECTORS {
790
            let keys: [u8; 64] = unhex(keys);
791
            let mut nonce: [u8; 16] = unhex(nonce);
792
            let mut uiv: uiv::Uiv<Aes128, Aes128> = uiv::Uiv::initialize(&keys).unwrap();
793
            let expect_keys: [u8; 64] = unhex(expect_keys);
794
            let expect_nonce: [u8; 16] = unhex(expect_nonce);
795
            uiv.update(&mut nonce);
796
            assert_eq!(&nonce, &expect_nonce);
797
            assert_eq!(&uiv.keys[..], &expect_keys[..]);
798

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

            
803
            let tweak: [u8; 16] = rng.random();
804
            let cmd = rng.random();
805
            let mut msg1: [u8; CELL_DATA_LEN] = rng.random();
806
            let mut msg2 = msg1.clone();
807

            
808
            uiv.encrypt((&tweak, cmd), &mut msg1);
809
            uiv2.encrypt((&tweak, cmd), &mut msg2);
810
        }
811
    }
812

            
813
    #[test]
814
    fn testvec_cgo_relay() {
815
        for (inbound, (k, n, tprime), ad, t, c, output) in CGO_RELAY_TEST_VECTORS {
816
            let k_n: [u8; 80] = unhex(&format!("{k}{n}"));
817
            let tprime: [u8; 16] = unhex(tprime);
818
            let ad: [u8; 1] = unhex(ad);
819
            let msg: [u8; CELL_DATA_LEN] = unhex(&format!("{t}{c}"));
820
            let mut msg = RelayCellBody(Box::new(msg));
821

            
822
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
823
            *state.tag = tprime;
824
            let state = if *inbound {
825
                let mut s = RelayInbound::from(state);
826
                s.encrypt_inbound(ad[0].into(), &mut msg);
827
                s.0
828
            } else {
829
                let mut s = RelayOutbound::from(state);
830
                s.decrypt_outbound(ad[0].into(), &mut msg);
831
                s.0
832
            };
833

            
834
            // expected values
835
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
836
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
837
            let ex_k: [u8; 64] = unhex(ex_k);
838
            let ex_n: [u8; 16] = unhex(ex_n);
839
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
840
            assert_eq!(&ex_msg[..], &msg.0[..]);
841
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
842
            assert_eq!(&state.nonce[..], &ex_n[..]);
843
            assert_eq!(&state.tag[..], &ex_tprime[..]);
844
        }
845
    }
846

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

            
858
            let mut state = CryptState::<Aes128, Aes128>::initialize(&k_n).unwrap();
859
            *state.tag = tprime;
860
            let mut state = RelayInbound::from(state);
861
            state.originate(ad[0].into(), &mut msg);
862
            let state = state.0;
863

            
864
            let ((ex_k, ex_n, ex_tprime), (ex_t, ex_c)) = output;
865
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
866
            let ex_k: [u8; 64] = unhex(ex_k);
867
            let ex_n: [u8; 16] = unhex(ex_n);
868
            let ex_tprime: [u8; 16] = unhex(ex_tprime);
869
            assert_eq!(&ex_msg[..], &msg.0[..]);
870
            assert_eq!(&state.uiv.keys[..], &ex_k[..]);
871
            assert_eq!(&state.nonce[..], &ex_n[..]);
872
            assert_eq!(&state.tag[..], &ex_tprime[..]);
873
        }
874
    }
875

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

            
891
            let ad: [u8; 1] = unhex(ad);
892
            let msg_body: [u8; CGO_PAYLOAD_LEN] = unhex(m);
893
            let mut msg = [0_u8; CELL_DATA_LEN];
894
            msg[16..].copy_from_slice(&msg_body[..]);
895
            let mut msg = RelayCellBody(Box::new(msg));
896
            let mut msg2 = msg.clone();
897

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

            
914
            let (ex_ss, (ex_t, ex_c)) = output;
915
            let ex_msg: [u8; CELL_DATA_LEN] = unhex(&format!("{ex_t}{ex_c}"));
916
            assert_eq!(&ex_msg[..], &msg.0[..]);
917

            
918
            for (layer, (ex_k, ex_n, ex_tprime)) in individual_layers.iter().zip(ex_ss.iter()) {
919
                let state = &layer.0;
920
                let ex_k: [u8; 64] = unhex(ex_k);
921
                let ex_n: [u8; 16] = unhex(ex_n);
922
                let ex_tprime: [u8; 16] = unhex(ex_tprime);
923

            
924
                assert_eq!(&state.uiv.keys[..], &ex_k[..]);
925
                assert_eq!(&state.nonce[..], &ex_n[..]);
926
                assert_eq!(&state.tag[..], &ex_tprime);
927
            }
928
        }
929
    }
930
}