tor_proto/crypto/binding.rs
1//! Types related to binding messages to specific circuits
2
3#[cfg(feature = "hs-service")]
4use tor_hscrypto::ops::HsMacKey;
5use zeroize::Zeroizing;
6
7/// Number of bytes of circuit binding material negotiated per circuit hop.
8pub(crate) const CIRC_BINDING_LEN: usize = 20;
9
10/// Cryptographic information used to bind a message to a specific circuit.
11///
12/// This information is used in some of our protocols (currently only the onion
13/// services protocol) to prove that a given message was referring to a specific
14/// hop on a specific circuit, and was not replayed from another circuit.
15///
16/// In `tor-spec` and `rend-spec`, this value is called `KH`.
17#[derive(Clone)]
18pub struct CircuitBinding(
19 // We use a Box here to avoid moves that would bypass the zeroize-on-drop
20 // semantics.
21 //
22 // (This is not super-critical, since the impact of leaking one of these
23 // keys is slight, but it's best not to leak them at all.)
24 Box<Zeroizing<[u8; CIRC_BINDING_LEN]>>,
25);
26
27impl From<[u8; CIRC_BINDING_LEN]> for CircuitBinding {
28 fn from(value: [u8; CIRC_BINDING_LEN]) -> Self {
29 Self(Box::new(Zeroizing::new(value)))
30 }
31}
32
33impl TryFrom<&[u8]> for CircuitBinding {
34 type Error = crate::Error;
35
36 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
37 let value: &[u8; CIRC_BINDING_LEN] = &value
38 .try_into()
39 .or(Err(Self::Error::InvalidKDFOutputLength))?;
40 Ok(Self::from(*value))
41 }
42}
43
44impl CircuitBinding {
45 /// Return a view of this key suitable for computing the MAC function used
46 /// to authenticate onion services' ESTABLISH_INTRODUCE messages.
47 ///
48 /// Note that this is not a general-purpose MAC; please avoid adding new
49 /// users of it. See notes on [`hs_mac`](tor_hscrypto::ops::hs_mac) for
50 /// more information.
51 #[cfg(feature = "hs-service")]
52 pub fn hs_mac(&self) -> HsMacKey<'_> {
53 HsMacKey::from(self.dangerously_into_bytes())
54 }
55
56 /// Return a view of this key as a byte-slice.
57 ///
58 /// This is potentially dangerous, since we don't want to expose this
59 /// information: We only want to use it as a MAC key.
60 #[cfg(feature = "hs-service")]
61 fn dangerously_into_bytes(&self) -> &[u8] {
62 &(**self.0)[..]
63 }
64}