tor_proto/crypto/handshake/
fast.rs

1//! Implementation for the (deprecated) CreateFast handshake.
2//!
3
4use std::borrow::Borrow;
5
6use super::{RelayHandshakeError, RelayHandshakeResult};
7use crate::crypto::ll::kdf::{Kdf, LegacyKdf};
8use crate::util::ct::bytes_eq;
9use crate::{Error, Result};
10
11use rand::{CryptoRng, RngCore};
12use tor_bytes::SecretBuf;
13use tor_error::into_internal;
14
15/// Number of bytes used for a "CREATE_FAST" handshake by the initiator.
16pub(crate) const FAST_C_HANDSHAKE_LEN: usize = 20;
17/// Number of bytes used for a "CREATE_FAST" handshake by the responder
18pub(crate) const FAST_S_HANDSHAKE_LEN: usize = 20 * 2;
19
20/// State for a CREATE_FAST client handshake.
21pub(crate) struct CreateFastClientState([u8; FAST_C_HANDSHAKE_LEN]);
22
23/// Client-handshake for CREATE_FAST.
24///
25/// See module documentation; you probably don't want to use this.
26pub(crate) struct CreateFastClient;
27
28/// How many bytes does this handshake use for its input seed?
29const SECRET_INPUT_LEN: usize = 40;
30
31impl super::ClientHandshake for CreateFastClient {
32    type KeyType = ();
33    type StateType = CreateFastClientState;
34    type KeyGen = super::TapKeyGenerator;
35    type ClientAuxData = ();
36    type ServerAuxData = ();
37
38    fn client1<R: RngCore + CryptoRng, M: Borrow<()>>(
39        rng: &mut R,
40        _key: &Self::KeyType,
41        _client_aux_data: &M,
42    ) -> Result<(Self::StateType, Vec<u8>)> {
43        let mut state = [0_u8; FAST_C_HANDSHAKE_LEN];
44        rng.fill_bytes(&mut state);
45        Ok((CreateFastClientState(state), state.into()))
46    }
47
48    fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<((), Self::KeyGen)> {
49        let msg = msg.as_ref();
50        if msg.len() != FAST_S_HANDSHAKE_LEN {
51            return Err(Error::BadCircHandshakeAuth);
52        }
53        // There is not necessarily much point here (and below) in using a
54        // SecretBuf, since the data at issue are already in a cell that
55        // _wasn't_ marked with Zeroize.  Still, for consistency, we use it
56        // here.
57        let mut inp = SecretBuf::with_capacity(SECRET_INPUT_LEN);
58        inp.extend_from_slice(&state.0[..]);
59        inp.extend_from_slice(&msg[0..20]);
60
61        let kh_expect = LegacyKdf::new(0).derive(&inp[..], 20)?;
62
63        if !bytes_eq(&kh_expect, &msg[20..40]) {
64            return Err(Error::BadCircHandshakeAuth);
65        }
66
67        Ok(((), super::TapKeyGenerator::new(inp)))
68    }
69}
70
71/// Relay-handshake for CREATE_FAST.
72///
73/// See module documentation; you probably don't want to use this.
74#[allow(dead_code)] // TODO #1467
75pub(crate) struct CreateFastServer;
76
77impl super::ServerHandshake for CreateFastServer {
78    type KeyType = ();
79    type KeyGen = super::TapKeyGenerator;
80    type ClientAuxData = ();
81    type ServerAuxData = ();
82
83    fn server<R: RngCore + CryptoRng, REPLY: super::AuxDataReply<Self>, T: AsRef<[u8]>>(
84        rng: &mut R,
85        reply_fn: &mut REPLY,
86        _key: &[Self::KeyType],
87        msg: T,
88    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)> {
89        let _reply_extensions: () = reply_fn
90            .reply(&())
91            .ok_or(RelayHandshakeError::BadClientHandshake)?;
92
93        let msg = msg.as_ref();
94        if msg.len() != FAST_C_HANDSHAKE_LEN {
95            return Err(RelayHandshakeError::BadClientHandshake);
96        }
97        let mut reply = vec![0_u8; FAST_S_HANDSHAKE_LEN];
98        rng.fill_bytes(&mut reply[0..20]);
99
100        let mut inp = SecretBuf::with_capacity(SECRET_INPUT_LEN);
101        inp.extend_from_slice(msg);
102        inp.extend_from_slice(&reply[0..20]);
103        let kh = LegacyKdf::new(0)
104            .derive(&inp[..], 20)
105            .map_err(into_internal!("Can't expand key"))?;
106        reply[20..].copy_from_slice(&kh);
107
108        Ok((super::TapKeyGenerator::new(inp), reply))
109    }
110}
111
112#[cfg(test)]
113mod test {
114    // @@ begin test lint list maintained by maint/add_warning @@
115    #![allow(clippy::bool_assert_comparison)]
116    #![allow(clippy::clone_on_copy)]
117    #![allow(clippy::dbg_macro)]
118    #![allow(clippy::mixed_attributes_style)]
119    #![allow(clippy::print_stderr)]
120    #![allow(clippy::print_stdout)]
121    #![allow(clippy::single_char_pattern)]
122    #![allow(clippy::unwrap_used)]
123    #![allow(clippy::unchecked_duration_subtraction)]
124    #![allow(clippy::useless_vec)]
125    #![allow(clippy::needless_pass_by_value)]
126    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
127    use super::*;
128    use crate::crypto::handshake::{ClientHandshake, KeyGenerator, ServerHandshake};
129    use hex_literal::hex;
130    use tor_basic_utils::test_rng::testing_rng;
131
132    #[test]
133    fn roundtrip() {
134        let mut rng = testing_rng();
135
136        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
137        let (s_kg, smsg) =
138            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
139        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
140
141        let s_key = s_kg.expand(200).unwrap();
142        let c_key = c_kg.expand(200).unwrap();
143
144        assert_eq!(s_key, c_key);
145    }
146
147    #[test]
148    fn failure() {
149        let mut rng = testing_rng();
150
151        // badly formatted client message.
152        let cmsg = [6_u8; 19];
153        let ans = CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg);
154        assert!(ans.is_err());
155
156        // corrupt/ incorrect server reply.
157        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
158        let (_, mut smsg) =
159            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
160        smsg[35] ^= 16;
161        let ans = CreateFastClient::client2(state, smsg);
162        assert!(ans.is_err());
163    }
164
165    fn test_one_handshake(cmsg: [u8; 20], smsg: [u8; 40], keys: [u8; 100]) {
166        use crate::crypto::testing::FakePRNG;
167
168        let mut rng = FakePRNG::new(&cmsg);
169        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
170
171        let mut rng = FakePRNG::new(&smsg);
172        let (s_kg, smsg) =
173            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
174        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
175
176        let s_key = s_kg.expand(100).unwrap();
177        let c_key = c_kg.expand(100).unwrap();
178
179        assert_eq!(s_key, c_key);
180        assert_eq!(&s_key[..], &keys[..]);
181    }
182
183    #[test]
184    fn testvec() {
185        // Generated from Tor.
186        test_one_handshake(
187            hex!("080E247DF7C252FCD2DC10F459703480C223E3A6"),
188            hex!("BA95C0D092335428BF80093BBED0B7A26C49E1E8696FBF9C8D6BE26504219C000D26AFE370FCEF04"),
189            hex!("AFA89B4FC8CF882335A582C52478B5FCB1E08DAF707E2C2D23B8C27D30BD461F3DF98A3AF82221CB658AD0AA8680B99067E4F7DBC546970EA9A56B26433C71DA867BDD09C14A1308BC327D6A448D71D2382B3AB6AF0BB4E19649A8DFF607DB9C57A04AC3"));
190
191        test_one_handshake(
192            hex!("5F786C724C2F5978474A04FA63772057AD896A03"),
193            hex!("6210B037001405742FE78B6F5B34E6DB3C9F2F7E24239498613E0ED872E110A00774A3FCB37A7507"),
194            hex!("D41B65D83FB4B34A322B658BE4D706EDCD8B62813757E719118C394E1F22E1C8EA8959BAB30E856A914C3054946F547397094DE031F5BCA384C65C8880BF7AAB9CE7BEE33971F9DE8C22A23366F46BF8B5E5112321E216B0E02C62EEA3ABB72A0E062592"));
195    }
196}