bramble_qr/
protocol.rs

1//! BQP key agreement protocol
2
3use crate::{Error, Payload, Result, BETA_VERSION, CURRENT_VERSION};
4use bramble_crypto::{
5    hash, kdf, kex, mac, KeyPair, Mac, PublicKey, Role, SymmetricKey, KEY_LEN, MAC_LEN,
6};
7use bramble_data::custom::array_as_bytes;
8use futures::{AsyncRead, AsyncWrite};
9use serde::{Deserialize, Serialize};
10use std::{
11    fmt::{self, Debug},
12    pin::Pin,
13    slice,
14};
15
16/// Perform the QR code key agreement protocol over the given transport
17pub async fn perform_key_agreement<T>(
18    transport: T,
19    our_payload: Payload,
20    our_kp: KeyPair,
21    their_payload: Payload,
22) -> Result<(SymmetricKey, Role)>
23where
24    T: AsyncRead + AsyncWrite,
25{
26    let our_bytes = our_payload.to_bytes();
27    let their_bytes = their_payload.to_bytes();
28    let role = if our_bytes < their_bytes {
29        Role::Alice
30    } else {
31        Role::Bob
32    };
33    let protocol = Protocol {
34        transport: Box::pin(transport),
35        role,
36        our_payload,
37        our_kp,
38        their_payload,
39    };
40    Ok((protocol.perform().await?, role))
41}
42
43struct Protocol<T>
44where
45    T: AsyncRead + AsyncWrite,
46{
47    transport: Pin<Box<T>>,
48    role: Role,
49    our_payload: Payload,
50    our_kp: KeyPair,
51    their_payload: Payload,
52}
53
54impl<T> Protocol<T>
55where
56    T: AsyncRead + AsyncWrite,
57{
58    pub async fn perform(mut self) -> Result<SymmetricKey> {
59        match self.perform_inner().await {
60            Err(e) => {
61                self.send_abort(&e).await?;
62                Err(e)
63            }
64            ok => ok,
65        }
66    }
67
68    async fn perform_inner(&mut self) -> Result<SymmetricKey> {
69        let their_pk = if self.role == Role::Alice {
70            self.send_key().await?;
71            self.receive_key().await?
72        } else {
73            let their_pk = self.receive_key().await?;
74            self.send_key().await?;
75            their_pk
76        };
77
78        let ss = self.derive_shared_secret(&their_pk)?;
79        if self.role == Role::Alice {
80            self.send_confirm(&ss, &their_pk).await?;
81            self.receive_confirm(&ss, &their_pk).await?;
82        } else {
83            self.receive_confirm(&ss, &their_pk).await?;
84            self.send_confirm(&ss, &their_pk).await?;
85        }
86        Ok(self.derive_master_secret(&ss))
87    }
88
89    async fn send_key(&mut self) -> Result<()> {
90        use futures::io::AsyncWriteExt;
91
92        let mut buf = [0u8; KEY_RECORD_LEN];
93        let (version, slice) = buf.split_at_mut(1);
94        let (typ, slice) = slice.split_at_mut(1);
95        let (len, key) = slice.split_at_mut(2);
96        version.copy_from_slice(&CURRENT_VERSION.to_be_bytes());
97        typ.copy_from_slice(&KEY_RECORD_TYPE.to_be_bytes());
98        len.copy_from_slice(&(KEY_LEN as u16).to_be_bytes());
99        key.copy_from_slice(self.our_kp.public().as_ref());
100        self.transport.write_all(&buf).await?;
101        Ok(())
102    }
103
104    async fn receive_key(&mut self) -> Result<PublicKey> {
105        use futures::io::AsyncReadExt;
106
107        let _version = self.read_version().await?;
108
109        let mut record_type = 0u8;
110        self.transport
111            .read_exact(slice::from_mut(&mut record_type))
112            .await?;
113        if record_type != KEY_RECORD_TYPE {
114            return Err(Error::InvalidRecord);
115        }
116
117        let mut len_bytes = [0u8; 2];
118        self.transport.read_exact(&mut len_bytes).await?;
119        let len = u16::from_be_bytes(len_bytes);
120        if len as usize != KEY_LEN {
121            return Err(Error::InvalidKey);
122        }
123
124        let mut pk_bytes = [0u8; KEY_LEN];
125        self.transport.read_exact(&mut pk_bytes).await?;
126        let pk = PublicKey::from(pk_bytes);
127        let expected = Commit::derive(&pk);
128        if self.their_payload.commit() == expected {
129            Ok(pk)
130        } else {
131            Err(Error::InvalidKey)
132        }
133    }
134
135    async fn send_confirm(&mut self, ss: &SymmetricKey, their_pk: &PublicKey) -> Result<()> {
136        use futures::io::AsyncWriteExt;
137
138        let confirm = self.derive_confirmation_code(ss, their_pk, self.role);
139        let mut buf = [0u8; CONFIRM_RECORD_LEN];
140        let (version, slice) = buf.split_at_mut(1);
141        let (typ, slice) = slice.split_at_mut(1);
142        let (len, key) = slice.split_at_mut(2);
143        version.copy_from_slice(&CURRENT_VERSION.to_be_bytes());
144        typ.copy_from_slice(&CONFIRM_RECORD_TYPE.to_be_bytes());
145        len.copy_from_slice(&(MAC_LEN as u16).to_be_bytes());
146        key.copy_from_slice(confirm.as_ref());
147        self.transport.write_all(&buf).await?;
148        Ok(())
149    }
150
151    async fn receive_confirm(&mut self, ss: &SymmetricKey, their_pk: &PublicKey) -> Result<()> {
152        use futures::io::AsyncReadExt;
153
154        let _version = self.read_version().await?;
155
156        let mut record_type = 0u8;
157        self.transport
158            .read_exact(slice::from_mut(&mut record_type))
159            .await?;
160        if record_type != CONFIRM_RECORD_TYPE {
161            return Err(Error::InvalidRecord);
162        }
163
164        let mut len_bytes = [0u8; 2];
165        self.transport.read_exact(&mut len_bytes).await?;
166        let len = u16::from_be_bytes(len_bytes);
167        if len as usize != MAC_LEN {
168            return Err(Error::InvalidConfirmation);
169        }
170
171        let mut confirm_bytes = [0u8; MAC_LEN];
172        self.transport.read_exact(&mut confirm_bytes).await?;
173
174        let confirm = Mac::from(confirm_bytes);
175        let expected = self.derive_confirmation_code(ss, their_pk, self.role.opposite());
176        confirm
177            .verify(&expected)
178            .map_err(|_| Error::InvalidConfirmation)
179    }
180
181    async fn send_abort(&mut self, _e: &Error) -> Result<()> {
182        use futures::io::AsyncWriteExt;
183
184        let mut buf = [0u8; ABORT_RECORD_LEN];
185        let (version, slice) = buf.split_at_mut(1);
186        let (typ, len) = slice.split_at_mut(1);
187        version.copy_from_slice(&CURRENT_VERSION.to_be_bytes());
188        typ.copy_from_slice(&ABORT_RECORD_TYPE.to_be_bytes());
189        len.copy_from_slice(&0u16.to_be_bytes());
190        self.transport.write_all(&buf).await?;
191        Ok(())
192    }
193
194    async fn read_version(&mut self) -> Result<u8> {
195        use futures::io::AsyncReadExt;
196
197        let mut version = 0u8;
198        self.transport
199            .read_exact(slice::from_mut(&mut version))
200            .await?;
201        if version == BETA_VERSION {
202            return Err(Error::BetaVersion);
203        }
204        if version < CURRENT_VERSION {
205            return Err(Error::OlderVersion);
206        }
207        if version > CURRENT_VERSION {
208            return Err(Error::NewerVersion);
209        }
210        Ok(version)
211    }
212
213    fn derive_shared_secret(&self, their_pk: &PublicKey) -> Result<SymmetricKey> {
214        let (alice_pk, bob_pk) = match self.role {
215            Role::Alice => (self.our_kp.public(), their_pk),
216            Role::Bob => (their_pk, self.our_kp.public()),
217        };
218        kex(
219            SHARED_SECRET_LABEL,
220            self.our_kp.secret(),
221            their_pk,
222            &[&[CURRENT_VERSION], alice_pk.as_ref(), bob_pk.as_ref()],
223        )
224    }
225
226    fn derive_master_secret(&self, ss: &SymmetricKey) -> SymmetricKey {
227        kdf(MASTER_SECRET_LABEL, ss, &[])
228    }
229
230    fn derive_confirmation_code(
231        &self,
232        ss: &SymmetricKey,
233        their_pk: &PublicKey,
234        target: Role,
235    ) -> Mac {
236        let confirmation_key = kdf(CONFIRMATION_KEY_LABEL, ss, &[]);
237        let our_payload = self.our_payload.to_bytes();
238        let their_payload = self.their_payload.to_bytes();
239        let inputs = if self.role == target {
240            [
241                &our_payload,
242                self.our_kp.public().as_ref(),
243                &their_payload,
244                their_pk.as_ref(),
245            ]
246        } else {
247            [
248                &their_payload,
249                their_pk.as_ref(),
250                &our_payload,
251                self.our_kp.public().as_ref(),
252            ]
253        };
254        mac(CONFIRMATION_MAC_LABEL, &confirmation_key, &inputs)
255    }
256}
257
258/// A public key commitment
259#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
260#[serde(transparent)]
261pub struct Commit(#[serde(with = "array_as_bytes")] [u8; COMMIT_LEN]);
262
263impl AsRef<[u8]> for Commit {
264    fn as_ref(&self) -> &[u8] {
265        &self.0
266    }
267}
268
269impl From<[u8; COMMIT_LEN]> for Commit {
270    fn from(buf: [u8; COMMIT_LEN]) -> Self {
271        Self(buf)
272    }
273}
274
275impl Debug for Commit {
276    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
277        write!(fmt, "{}", hex::encode(self.0))
278    }
279}
280
281impl Commit {
282    /// Derives a new public key commitment
283    pub fn derive(pk: &PublicKey) -> Self {
284        let h = hash(COMMIT_LABEL, &[pk.as_ref()]);
285        let mut buf = [0u8; COMMIT_LEN];
286        buf.copy_from_slice(&h.as_ref()[..COMMIT_LEN]);
287        Self::from(buf)
288    }
289}
290
291const COMMIT_LEN: usize = 16;
292const COMMIT_LABEL: &[u8] = b"org.briarproject.bramble.keyagreement/COMMIT";
293const MASTER_SECRET_LABEL: &[u8] = b"org.briarproject.bramble.keyagreement/MASTER_SECRET";
294const SHARED_SECRET_LABEL: &[u8] = b"org.briarproject.bramble.keyagreement/SHARED_SECRET";
295const CONFIRMATION_KEY_LABEL: &[u8] = b"org.briarproject.bramble.keyagreement/CONFIRMATION_KEY";
296const CONFIRMATION_MAC_LABEL: &[u8] = b"org.briarproject.bramble.keyagreement/CONFIRMATION_MAC";
297
298const RECORD_HEADER_LEN: usize = 1 + 1 + 2;
299const KEY_RECORD_LEN: usize = RECORD_HEADER_LEN + KEY_LEN;
300const CONFIRM_RECORD_LEN: usize = RECORD_HEADER_LEN + MAC_LEN;
301const ABORT_RECORD_LEN: usize = RECORD_HEADER_LEN;
302const KEY_RECORD_TYPE: u8 = 0;
303const CONFIRM_RECORD_TYPE: u8 = 1;
304const ABORT_RECORD_TYPE: u8 = 2;
305
306#[cfg(test)]
307mod test {
308    use super::*;
309    use crate::Descriptor;
310    use bramble_common::make_duplex;
311    use futures::{executor::block_on, try_join};
312    use rand::thread_rng;
313
314    #[test]
315    fn both_sides_compute_the_same_master_secret() {
316        let transport = Descriptor::unknown(89, vec![]);
317
318        let mut rng = thread_rng();
319        let kp1 = KeyPair::generate(&mut rng);
320        let pk1 = kp1.public();
321        let payload1 = Payload::new(&pk1, vec![transport.clone()]);
322
323        let mut rng = thread_rng();
324        let kp2 = KeyPair::generate(&mut rng);
325        let pk2 = kp2.public();
326        let payload2 = Payload::new(&pk2, vec![transport.clone()]);
327
328        let (transport1, transport2) = make_duplex();
329
330        let fut1 = perform_key_agreement(transport1, payload1.clone(), kp1, payload2.clone());
331        let fut2 = perform_key_agreement(transport2, payload2, kp2, payload1);
332
333        let ((master_key1, role1), (master_key2, role2)) =
334            block_on(async { try_join!(fut1, fut2) }).unwrap();
335
336        assert_eq!(master_key1, master_key2);
337        assert_ne!(role1, role2);
338    }
339}