1use 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
16pub 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#[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 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}