Skip to main content

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, Rng};
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: Rng + 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: Rng + 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_time_subtraction)]
124    #![allow(clippy::useless_vec)]
125    #![allow(clippy::needless_pass_by_value)]
126    #![allow(clippy::string_slice)] // See arti#2571
127    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
128    use super::*;
129    use crate::crypto::handshake::{ClientHandshake, KeyGenerator, ServerHandshake};
130    use hex_literal::hex;
131    use tor_basic_utils::test_rng::testing_rng;
132
133    #[test]
134    fn roundtrip() {
135        let mut rng = testing_rng();
136
137        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
138        let (s_kg, smsg) =
139            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
140        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
141
142        let s_key = s_kg.expand(200).unwrap();
143        let c_key = c_kg.expand(200).unwrap();
144
145        assert_eq!(s_key, c_key);
146    }
147
148    #[test]
149    fn failure() {
150        let mut rng = testing_rng();
151
152        // badly formatted client message.
153        let cmsg = [6_u8; 19];
154        let ans = CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg);
155        assert!(ans.is_err());
156
157        // corrupt/ incorrect server reply.
158        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
159        let (_, mut smsg) =
160            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
161        smsg[35] ^= 16;
162        let ans = CreateFastClient::client2(state, smsg);
163        assert!(ans.is_err());
164    }
165
166    fn test_one_handshake(cmsg: [u8; 20], smsg: [u8; 40], keys: [u8; 100]) {
167        use crate::crypto::testing::FakePRNG;
168
169        let mut rng = FakePRNG::new(&cmsg);
170        let (state, cmsg) = CreateFastClient::client1(&mut rng, &(), &()).unwrap();
171
172        let mut rng = FakePRNG::new(&smsg);
173        let (s_kg, smsg) =
174            CreateFastServer::server(&mut rng, &mut |_: &()| Some(()), &[()], cmsg).unwrap();
175        let (_msg, c_kg) = CreateFastClient::client2(state, smsg).unwrap();
176
177        let s_key = s_kg.expand(100).unwrap();
178        let c_key = c_kg.expand(100).unwrap();
179
180        assert_eq!(s_key, c_key);
181        assert_eq!(&s_key[..], &keys[..]);
182    }
183
184    #[test]
185    fn testvec() {
186        // Generated from Tor.
187        test_one_handshake(
188            hex!("080E247DF7C252FCD2DC10F459703480C223E3A6"),
189            hex!(
190                "BA95C0D092335428BF80093BBED0B7A26C49E1E8696FBF9C8D6BE26504219C000D26AFE370FCEF04"
191            ),
192            hex!(
193                "AFA89B4FC8CF882335A582C52478B5FCB1E08DAF707E2C2D23B8C27D30BD461F3DF98A3AF82221CB658AD0AA8680B99067E4F7DBC546970EA9A56B26433C71DA867BDD09C14A1308BC327D6A448D71D2382B3AB6AF0BB4E19649A8DFF607DB9C57A04AC3"
194            ),
195        );
196
197        test_one_handshake(
198            hex!("5F786C724C2F5978474A04FA63772057AD896A03"),
199            hex!(
200                "6210B037001405742FE78B6F5B34E6DB3C9F2F7E24239498613E0ED872E110A00774A3FCB37A7507"
201            ),
202            hex!(
203                "D41B65D83FB4B34A322B658BE4D706EDCD8B62813757E719118C394E1F22E1C8EA8959BAB30E856A914C3054946F547397094DE031F5BCA384C65C8880BF7AAB9CE7BEE33971F9DE8C22A23366F46BF8B5E5112321E216B0E02C62EEA3ABB72A0E062592"
204            ),
205        );
206    }
207}