p2panda_encryption/two_party/
two_party.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Two-Party Secure Messaging (2SM) Key Agreement Protocol.
4use std::collections::HashMap;
5use std::marker::PhantomData;
6
7use p2panda_core::cbor::{DecodeError, EncodeError, decode_cbor, encode_cbor};
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11use crate::crypto::hpke::{HpkeCiphertext, HpkeError, hpke_open, hpke_seal};
12use crate::crypto::x25519::{PublicKey, SecretKey, X25519Error};
13use crate::crypto::{Rng, RngError};
14use crate::key_bundle::{LongTermKeyBundle, OneTimeKeyBundle, PreKeyId};
15use crate::key_manager::KeyManager;
16use crate::traits::{IdentityManager, KeyBundle, PreKeyManager};
17use crate::two_party::{X3dhCiphertext, X3dhError, x3dh_decrypt, x3dh_encrypt};
18
19/// Two-Party Secure Messaging (2SM) Key Agreement Protocol as specified in the paper "Key
20/// Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees" (2020).
21///
22/// 2SM is used for key-agreement as part of the DCGKA protocol allowing all members to learn about
23/// the "seed" for establishing new secret state. 2SM is pair-wise between all members of an
24/// encrypted group. p2panda uses 2SM for both "data-" and "message encryption" schemes.
25///
26/// ## Protocol
27///
28/// An initiator "Alice" of a 2SM session uses the pre-keys of "Bob" to send the first encrypted
29/// message using the X3DH protocol. This only takes place once and the pre-keys can be considered
30/// "used" afterwards (which is especially important for one-time pre-keys).
31///
32/// All subsequent messages sent between Alice and Bob are encrypted using the HPKE protocol. For
33/// each round the sender uses the previous keys for HPKE and generates and attaches to the payload
34/// a new key-pair for future rounds.
35///
36/// To avoid reusing public keys (which would make FS impossible), whenever a party sends a
37/// message, it also updates the other party's public key. To do so, it sends a new secret key
38/// along with its message, then deletes its own copy, storing only the public key.
39///
40/// To accommodate for messages arriving "late", the secret key is kept until it or a newer secret
41/// has been used. In the case of a newer secret being used, all "previous" secret keys will be
42/// dropped.
43///
44/// ## Forward secrecy
45///
46/// During the initial 2SM "round" using X3DH the forward secrecy is defined by the lifetime of the
47/// used pre-keys. For strong security guarantees it is recommended to use one-time pre-keys. If
48/// this requirement can be relaxed it is possible to use long-term pre-keys, with a lifetime
49/// defined by the application.
50///
51/// Each subsequent 2SM HPKE round uses exactly one secret key, which is then dropped and replaced
52/// by a newly-generated key-pair. This gives the key-agreement protocol strong forward secrecy
53/// guarantees for each round, independent of the used pre-keys.
54///
55/// ## Cost of key-agreements
56///
57/// To make a group aware of a new secret key we could encrypt the secret pairwise with public-key
58/// encryption (PKE) towards each member of the group, resulting in an O(n^2) overhead as every
59/// member needs to share their secret with every other. The paper proposes an alternative approach
60/// with 2SM where a member prepares the next encryption keys not only for themselves but also for
61/// the other party, resulting in a more optimal O(n) cost when rotating keys. This allows us to
62/// "heal" the group in less steps after a member is removed.
63///
64/// ## Message Ordering
65///
66/// 2SM assumes that all messages are received in the order they have been sent. The application or
67/// underlying networking protocol needs to handle ordering. This is handled for us by the DCGKA
68/// protocol (as specified in the paper) and causally-ordered, authenticated broadcast in p2panda
69/// itself.
70///
71/// <https://eprint.iacr.org/2020/1281.pdf>
72pub struct TwoParty<KMG, KB> {
73    _marker: PhantomData<(KMG, KB)>,
74}
75
76/// 2SM protocol with one-time pre-keys.
77pub type OneTimeTwoParty = TwoParty<KeyManager, OneTimeKeyBundle>;
78
79/// 2SM protocol with long-term pre-keys (with a specified lifetime).
80pub type LongTermTwoParty = TwoParty<KeyManager, LongTermKeyBundle>;
81
82/// State of 2SM session between two members.
83///
84/// All 2SM methods are expressed as "pure functions" without any side-effects, returning an
85/// updated state object. This allows applications to be more crash-resiliant, persisting the final
86/// state only when all processes have successfully completed.
87///
88/// The state is serializable and can be used to persist 2SM sessions.
89#[derive(Debug, Serialize, Deserialize)]
90#[cfg_attr(any(test, feature = "test_utils"), derive(Clone))]
91pub struct TwoPartyState<KB: KeyBundle> {
92    /// Index of key we will use during next send. The receiver can use the public key and refer to
93    /// it through that index when they want to encrypt a message back to us.
94    our_next_key_index: u64,
95
96    /// Index of the last key which was used by the other peer to encrypt a message towards us. We
97    /// keep it around to understand which secret keys we can remove.
98    our_min_key_index: u64,
99
100    /// List of all secret keys we generated ourselves. We sent the public counterpart to the other
101    /// peer.
102    our_secret_keys: HashMap<u64, SecretKey>,
103
104    /// Last secret key the other peer generated for us. This is part of the 2SM protocol and an
105    /// optimization where the remote end can _also_ generate secrets for us.
106    our_received_secret_key: Option<SecretKey>,
107
108    /// Which key we use to decrypt the next incoming message.
109    their_next_key_used: KeyUsed,
110
111    /// Public identity key of the other peer. We use it to verify the signature of their prekey.
112    their_identity_key: PublicKey,
113
114    /// Key-material we need to encrypt the first message with the help of X3DH and prekeys.
115    their_prekey_bundle: Option<KB>,
116
117    /// Last known public key of the other peer. We use it to encrypt a message towards them.
118    their_public_key: Option<PublicKey>,
119}
120
121// Public methods.
122
123impl<KMG, KB> TwoParty<KMG, KB>
124where
125    KMG: IdentityManager<KMG::State> + PreKeyManager,
126    KB: KeyBundle,
127{
128    /// Initialise new 2SM state using the other party's pre-key bundle.
129    pub fn init(their_prekey_bundle: KB) -> TwoPartyState<KB> {
130        TwoPartyState {
131            our_next_key_index: 1,
132            our_min_key_index: 1,
133            our_secret_keys: HashMap::new(),
134            our_received_secret_key: None,
135            their_identity_key: *their_prekey_bundle.identity_key(),
136            their_public_key: None,
137            their_next_key_used: KeyUsed::PreKey,
138            their_prekey_bundle: Some(their_prekey_bundle),
139        }
140    }
141
142    /// Securely send a `plaintext` message to the other party.
143    pub fn send(
144        y: TwoPartyState<KB>,
145        y_manager: &KMG::State,
146        plaintext: &[u8],
147        rng: &Rng,
148    ) -> TwoPartyResult<(TwoPartyState<KB>, TwoPartyMessage)> {
149        let (for_us, for_them) = Self::generate_keys(rng)?;
150
151        let plaintext_message = TwoPartyPlaintext {
152            plaintext: plaintext.to_vec(),
153            receiver_new_secret: for_them.their_new_secret.clone(),
154            sender_new_public_key: for_them.our_new_public_key,
155            sender_next_index: y.our_next_key_index,
156        };
157        let plaintext_bytes = plaintext_message.to_bytes()?;
158
159        let (mut y_i, ciphertext) = Self::encrypt(y, y_manager, &plaintext_bytes, rng)?;
160
161        let message = TwoPartyMessage {
162            ciphertext,
163            key_used: y_i.their_next_key_used,
164        };
165
166        y_i.our_secret_keys
167            .insert(y_i.our_next_key_index, for_us.our_new_secret);
168        y_i.our_next_key_index += 1;
169
170        y_i.their_public_key = Some(for_us.their_new_public_key);
171
172        y_i.their_next_key_used = KeyUsed::ReceivedKey;
173
174        Ok((y_i, message))
175    }
176
177    /// Handle receiving a secure message from the other party.
178    pub fn receive(
179        y: TwoPartyState<KB>,
180        y_manager: KMG::State,
181        message: TwoPartyMessage,
182    ) -> TwoPartyResult<(TwoPartyState<KB>, KMG::State, Vec<u8>)> {
183        let (mut y_i, y_manager_i, plaintext_bytes) =
184            Self::decrypt(y, y_manager, message.ciphertext, message.key_used)?;
185        let plaintext_message = TwoPartyPlaintext::from_bytes(&plaintext_bytes)?;
186
187        y_i.their_public_key = Some(plaintext_message.sender_new_public_key);
188        y_i.their_next_key_used = KeyUsed::OwnKey(plaintext_message.sender_next_index);
189        y_i.our_received_secret_key = Some(plaintext_message.receiver_new_secret);
190
191        Ok((y_i, y_manager_i, plaintext_message.plaintext))
192    }
193}
194
195/// 2SM states indicating which key material was used.
196#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
197#[allow(clippy::enum_variant_names)]
198pub enum KeyUsed {
199    /// Previously published keys ("prekeys") for X3DH.
200    PreKey,
201
202    /// Key the receiving peer received last time from the sending peer for HPKE.
203    ReceivedKey,
204
205    /// Key the receiving peer generated themselves at some time. We can refer to the exact key by
206    /// it's index.
207    OwnKey(u64),
208}
209
210/// 2SM message to be sent over the network.
211///
212/// Note that this does not contain any additional information about the sender and receiver. This
213/// information needs to be added in applications.
214#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
215pub struct TwoPartyMessage {
216    ciphertext: TwoPartyCiphertext,
217    key_used: KeyUsed,
218}
219
220#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
221pub enum TwoPartyCiphertext {
222    /// Message was encrypted using X3DH pre-keys (initial round).
223    PreKey(X3dhCiphertext),
224
225    /// Message was encrypted using HPKE.
226    Hpke(HpkeCiphertext),
227}
228
229/// Payload from sender which will be encrypted containing the actual message `plaintext` and
230/// meta-data we need for the 2SM protocol.
231#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
232pub struct TwoPartyPlaintext {
233    /// Secret message for the receiver.
234    plaintext: Vec<u8>,
235
236    /// Newly generated secret for the receiver, to be used in future 2SM rounds.
237    receiver_new_secret: SecretKey,
238
239    /// Newly generated public key of the sender, to be used in future 2SM rounds.
240    sender_new_public_key: PublicKey,
241
242    /// Index of the newly generated key of the sender, the receiver refers to it when using it in
243    /// future 2SM rounds.
244    sender_next_index: u64,
245}
246
247impl TwoPartyPlaintext {
248    pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
249        decode_cbor(bytes)
250    }
251
252    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodeError> {
253        encode_cbor(&self)
254    }
255}
256
257// Private methods.
258
259impl<KMG, KB> TwoParty<KMG, KB>
260where
261    KMG: IdentityManager<KMG::State> + PreKeyManager,
262    KB: KeyBundle,
263{
264    /// Encrypt a message toward the other party using X3DH when it is the first round or HPKE for
265    /// subsequent rounds.
266    fn encrypt(
267        mut y: TwoPartyState<KB>,
268        y_manager: &KMG::State,
269        plaintext: &[u8],
270        rng: &Rng,
271    ) -> TwoPartyResult<(TwoPartyState<KB>, TwoPartyCiphertext)> {
272        let ciphertext = match &y.their_public_key {
273            None => {
274                // Establish secret via X3DH from prekey when no secret is given yet.
275                let their_prekey_bundle = y
276                    .their_prekey_bundle
277                    .take()
278                    .ok_or(TwoPartyError::PreKeyReuse)?;
279                let ciphertext = x3dh_encrypt(
280                    plaintext,
281                    KMG::identity_secret(y_manager),
282                    &their_prekey_bundle,
283                    rng,
284                )?;
285                TwoPartyCiphertext::PreKey(ciphertext)
286            }
287            Some(their_public_key) => {
288                let ciphertext = hpke_seal(their_public_key, None, None, plaintext)?;
289                TwoPartyCiphertext::Hpke(ciphertext)
290            }
291        };
292
293        Ok((y, ciphertext))
294    }
295
296    /// Decrypt a message from the other party using X3DH when it is the first round or HPKE for
297    /// subsequent rounds.
298    fn decrypt(
299        mut y: TwoPartyState<KB>,
300        y_manager: KMG::State,
301        ciphertext: TwoPartyCiphertext,
302        key_used: KeyUsed,
303    ) -> TwoPartyResult<(TwoPartyState<KB>, KMG::State, Vec<u8>)> {
304        let (y_manager_i, plaintext) = match key_used {
305            KeyUsed::PreKey => {
306                let TwoPartyCiphertext::PreKey(ciphertext) = ciphertext else {
307                    return Err(TwoPartyError::InvalidCiphertextType);
308                };
309
310                // If the underlying key manager provides a one-time secret, we use it here.
311                let (y_manager_i, onetime_secret) = match ciphertext.onetime_prekey_id {
312                    Some(onetime_prekey_id) => {
313                        let (y_manager_i, onetime_secret) =
314                            KMG::use_onetime_secret(y_manager, onetime_prekey_id)
315                                .map_err(|_| TwoPartyError::PreKeyReuse)?;
316                        (y_manager_i, onetime_secret)
317                    }
318                    None => (y_manager, None),
319                };
320
321                let plaintext = x3dh_decrypt(
322                    &ciphertext,
323                    KMG::identity_secret(&y_manager_i),
324                    KMG::prekey_secret(&y_manager_i, &ciphertext.prekey_id)
325                        // Fails when sender used an invalid / expired pre-key for initial X3DH.
326                        .map_err(|_| TwoPartyError::UnknownPreKeyUsed(ciphertext.prekey_id))?,
327                    onetime_secret.as_ref(),
328                )?;
329
330                (y_manager_i, plaintext)
331            }
332            KeyUsed::ReceivedKey => {
333                let TwoPartyCiphertext::Hpke(ciphertext) = ciphertext else {
334                    return Err(TwoPartyError::InvalidCiphertextType);
335                };
336
337                let Some(our_received_secret_key) = &y.our_received_secret_key else {
338                    return Err(TwoPartyError::UnknownSecretUsed(0));
339                };
340
341                let plaintext = hpke_open(&ciphertext, our_received_secret_key, None, None)?;
342                (y_manager, plaintext)
343            }
344            KeyUsed::OwnKey(index) => {
345                let TwoPartyCiphertext::Hpke(ciphertext) = ciphertext else {
346                    return Err(TwoPartyError::InvalidCiphertextType);
347                };
348
349                let plaintext = match y.our_secret_keys.get(&index) {
350                    Some(secret) => hpke_open(&ciphertext, secret, None, None)?,
351                    None => return Err(TwoPartyError::UnknownSecretUsed(index)),
352                };
353
354                for i in y.our_min_key_index..index + 1 {
355                    y.our_secret_keys.remove(&i);
356                }
357                y.our_min_key_index = index + 1;
358
359                (y_manager, plaintext)
360            }
361        };
362
363        Ok((y, y_manager_i, plaintext))
364    }
365}
366
367impl<KMG, KB> TwoParty<KMG, KB> {
368    /// Generate fresh key material for us and the other party for future 2SM rounds.
369    ///
370    /// This material is sent as part of the encrypted ciphertext, attached next to the actual
371    /// secret message. Each party prepares the received keys to be available for future rounds.
372    fn generate_keys(rng: &Rng) -> TwoPartyResult<(NewKeysForUs, NewKeysForThem)> {
373        let our_new_secret = SecretKey::from_bytes(rng.random_array()?);
374        let our_new_public_key = our_new_secret.public_key()?;
375
376        let their_new_secret = SecretKey::from_bytes(rng.random_array()?);
377        let their_new_public_key = their_new_secret.public_key()?;
378
379        Ok((
380            NewKeysForUs {
381                our_new_secret,
382                their_new_public_key,
383            },
384            NewKeysForThem {
385                our_new_public_key,
386                their_new_secret,
387            },
388        ))
389    }
390}
391
392struct NewKeysForUs {
393    our_new_secret: SecretKey,
394    their_new_public_key: PublicKey,
395}
396
397struct NewKeysForThem {
398    our_new_public_key: PublicKey,
399    their_new_secret: SecretKey,
400}
401
402pub type TwoPartyResult<T> = Result<T, TwoPartyError>;
403
404#[derive(Debug, Error)]
405pub enum TwoPartyError {
406    #[error(transparent)]
407    Hpke(#[from] HpkeError),
408
409    #[error(transparent)]
410    X3dh(#[from] X3dhError),
411
412    #[error(transparent)]
413    Rng(#[from] RngError),
414
415    #[error(transparent)]
416    Encode(#[from] EncodeError),
417
418    #[error(transparent)]
419    Decode(#[from] DecodeError),
420
421    #[error(transparent)]
422    X25519(#[from] X25519Error),
423
424    #[error("prekeys have already been used")]
425    PreKeyReuse,
426
427    #[error("tried to decrypt with unknown 2SM secret at index {0}")]
428    UnknownSecretUsed(u64),
429
430    #[error("tried to decrypt with unknown initial X3DH pre-key {0}")]
431    UnknownPreKeyUsed(PreKeyId),
432
433    #[error("invalid ciphertext for message type")]
434    InvalidCiphertextType,
435}
436
437#[cfg(test)]
438mod tests {
439    use crate::crypto::Rng;
440    use crate::crypto::x25519::SecretKey;
441    use crate::key_bundle::Lifetime;
442    use crate::key_manager::KeyManager;
443    use crate::traits::PreKeyManager;
444
445    use super::{KeyUsed, LongTermTwoParty, OneTimeTwoParty, TwoPartyError};
446
447    #[test]
448    fn two_party_secret_messaging_protocol() {
449        let rng = Rng::from_seed([1; 32]);
450
451        // Alice generates their key material.
452
453        let alice_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
454        let alice_manager =
455            KeyManager::init_and_generate_prekey(&alice_identity_secret, Lifetime::default(), &rng)
456                .unwrap();
457
458        let (alice_manager, alice_prekey_bundle) =
459            KeyManager::generate_onetime_bundle(alice_manager, &rng).unwrap();
460
461        // Bob generates their key material.
462
463        let bob_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
464        let bob_manager =
465            KeyManager::init_and_generate_prekey(&bob_identity_secret, Lifetime::default(), &rng)
466                .unwrap();
467
468        let (bob_manager, bob_prekey_bundle) =
469            KeyManager::generate_onetime_bundle(bob_manager, &rng).unwrap();
470
471        // Alice and Bob set up the 2SM protocol handlers for each other.
472
473        let alice_2sm = OneTimeTwoParty::init(bob_prekey_bundle);
474
475        // Alice doesn't have any secret HPKE keys yet and will use Bob's pre-keys for X3DH.
476        assert_eq!(alice_2sm.our_secret_keys.len(), 0);
477        assert_eq!(alice_2sm.our_min_key_index, 1);
478        assert_eq!(alice_2sm.our_next_key_index, 1);
479        assert_eq!(alice_2sm.their_next_key_used, KeyUsed::PreKey);
480
481        let bob_2sm = OneTimeTwoParty::init(alice_prekey_bundle);
482
483        // Bob doesn't have any secret HPKE keys yet and will use Alice's pre-keys for X3DH.
484        assert_eq!(bob_2sm.our_secret_keys.len(), 0);
485        assert_eq!(bob_2sm.our_min_key_index, 1);
486        assert_eq!(bob_2sm.our_next_key_index, 1);
487        assert_eq!(bob_2sm.their_next_key_used, KeyUsed::PreKey);
488
489        // They start exchanging "secret messages" to each other.
490
491        // 1. Alice sends a message to Bob using their pre-keys for X3DH.
492        let (alice_2sm, message_1) =
493            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"Hello, Bob!", &rng).unwrap();
494
495        // Alice generated their own secret key and sends the public part to Bob for future rounds.
496        assert_eq!(alice_2sm.our_secret_keys.len(), 1);
497        assert_eq!(alice_2sm.our_min_key_index, 1);
498        assert_eq!(alice_2sm.our_next_key_index, 2);
499
500        // Alice also generated the secret key for Bob, so Alice also knows their public key
501        // for the future already.
502        assert!(alice_2sm.their_public_key.is_some());
503
504        // Alice didn't receive anything from Bob yet.
505        assert!(alice_2sm.our_received_secret_key.is_none());
506
507        // In the future Alice would use the key they just generated to decrypt messages from Bob.
508        assert_eq!(alice_2sm.their_next_key_used, KeyUsed::ReceivedKey);
509
510        // Alice dropped the now-used pre-keys of Bob.
511        assert!(alice_2sm.their_prekey_bundle.is_none());
512
513        // 2. Bob receives Alice's message.
514        let (bob_2sm, bob_manager, receive_1) =
515            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_1).unwrap();
516
517        // Bob still doesn't have any generated keys yet.
518        assert_eq!(bob_2sm.our_secret_keys.len(), 0);
519        assert_eq!(bob_2sm.our_min_key_index, 1);
520        assert_eq!(bob_2sm.our_next_key_index, 1);
521
522        // Bob learned about the new public key (1) of Alice.
523        assert_eq!(
524            bob_2sm
525                .their_public_key
526                .expect("bob learned about public key of alice"),
527            alice_2sm
528                .our_secret_keys
529                .get(&1)
530                .expect("alice has one secret key")
531                .public_key()
532                .unwrap()
533        );
534
535        // Bob got their new secret key from Alice.
536        assert!(bob_2sm.our_received_secret_key.is_some());
537
538        // Bob would use Alice's new secret key for decrypting future messages.
539        assert_eq!(bob_2sm.their_next_key_used, KeyUsed::OwnKey(1));
540
541        // Bob still has Alice's pre-key bundle.
542        assert!(bob_2sm.their_prekey_bundle.is_some());
543
544        // 3. Alice sends another message to Bob and they receive it.
545        let (alice_2sm, message_2) =
546            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"How are you doing?", &rng).unwrap();
547        let (bob_2sm, bob_manager, receive_2) =
548            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_2).unwrap();
549
550        // Alice generated another secret and keeps now two of them around as Bob didn't reply yet.
551        assert_eq!(alice_2sm.our_secret_keys.len(), 2);
552        assert_eq!(alice_2sm.our_min_key_index, 1);
553        assert_eq!(alice_2sm.our_next_key_index, 3);
554
555        // The secret keys are unique for each round.
556        assert_ne!(
557            alice_2sm.our_secret_keys.get(&1).unwrap(),
558            alice_2sm.our_secret_keys.get(&2).unwrap(),
559        );
560
561        // Bob learned about the new public key (2) of Alice.
562        assert_eq!(
563            bob_2sm
564                .their_public_key
565                .expect("bob learned about public key of alice"),
566            alice_2sm
567                .our_secret_keys
568                .get(&2)
569                .expect("alice has one secret key")
570                .public_key()
571                .unwrap()
572        );
573
574        // 4. Bob answers to Alice.
575        let (bob_2sm, message_3) =
576            OneTimeTwoParty::send(bob_2sm, &bob_manager, b"I'm alright. Thank you!", &rng).unwrap();
577
578        // Bob used Alice's latest public key (2) to encrypt this message.
579        assert_eq!(message_3.key_used, KeyUsed::OwnKey(2));
580
581        // Bob generated their own secret key and sends the public part to Alice for future rounds.
582        assert_eq!(bob_2sm.our_secret_keys.len(), 1);
583        assert_eq!(bob_2sm.our_min_key_index, 1);
584        assert_eq!(bob_2sm.our_next_key_index, 2);
585
586        // Bob assumes now that Alice will use Bob's secret key for future messages.
587        assert_eq!(bob_2sm.their_next_key_used, KeyUsed::ReceivedKey);
588
589        // 5. Alice receives the message from Bob.
590        let (alice_2sm, alice_manager, receive_3) =
591            OneTimeTwoParty::receive(alice_2sm, alice_manager, message_3).unwrap();
592
593        // Alice removed the used secret key of this message (2) and all previous secrets as well
594        // (1) for forward secrecy.
595        assert_eq!(alice_2sm.our_secret_keys.len(), 0);
596        assert_eq!(alice_2sm.our_min_key_index, 3);
597        assert_eq!(alice_2sm.our_next_key_index, 3);
598
599        // 6. Both parties continue chatting with each other ..
600        let (bob_2sm, message_4) =
601            OneTimeTwoParty::send(bob_2sm, &bob_manager, b"How are you?", &rng).unwrap();
602        let (alice_2sm, alice_manager, receive_4) =
603            OneTimeTwoParty::receive(alice_2sm, alice_manager, message_4).unwrap();
604
605        let (alice_2sm, message_5) =
606            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"I'm bored.", &rng).unwrap();
607        let (bob_2sm, bob_manager, receive_5) =
608            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_5).unwrap();
609
610        // Messages can be correctly decrypted.
611        assert_eq!(receive_1, b"Hello, Bob!");
612        assert_eq!(receive_2, b"How are you doing?");
613        assert_eq!(receive_3, b"I'm alright. Thank you!");
614        assert_eq!(receive_4, b"How are you?");
615        assert_eq!(receive_5, b"I'm bored.");
616
617        // 7. They write a message to each other at the same time.
618        let (bob_2sm, message_6) =
619            OneTimeTwoParty::send(bob_2sm, &bob_manager, b":-(", &rng).unwrap();
620        let (alice_2sm, message_7) =
621            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"Oh wait.", &rng).unwrap();
622
623        let (alice_2sm, _, receive_6) =
624            OneTimeTwoParty::receive(alice_2sm, alice_manager, message_6).unwrap();
625        let (bob_2sm, _, receive_7) =
626            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_7).unwrap();
627
628        assert_eq!(receive_6, b":-(");
629        assert_eq!(receive_7, b"Oh wait.");
630
631        // Both Alice and Bob still only have one secret key and all other keys have been removed.
632        assert_eq!(alice_2sm.our_secret_keys.len(), 1);
633        assert_eq!(bob_2sm.our_secret_keys.len(), 1);
634    }
635
636    #[test]
637    fn long_term_prekeys() {
638        let rng = Rng::from_seed([1; 32]);
639
640        // Alice generates their long-term key material.
641
642        let alice_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
643        let alice_manager =
644            KeyManager::init_and_generate_prekey(&alice_identity_secret, Lifetime::default(), &rng)
645                .unwrap();
646
647        let alice_prekey_bundle = KeyManager::prekey_bundle(&alice_manager).unwrap();
648
649        // Bob generates their long-term key material.
650
651        let bob_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
652        let bob_manager =
653            KeyManager::init_and_generate_prekey(&bob_identity_secret, Lifetime::default(), &rng)
654                .unwrap();
655
656        let bob_prekey_bundle = KeyManager::prekey_bundle(&bob_manager).unwrap();
657
658        // Alice and Bob set up the 2SM protocol handlers for each other.
659
660        let alice_2sm_a = LongTermTwoParty::init(bob_prekey_bundle.clone());
661        let bob_2sm_a = LongTermTwoParty::init(alice_prekey_bundle.clone());
662
663        // They start exchanging "secret messages" to each other in Group A.
664
665        let (alice_2sm_a, message_1) =
666            LongTermTwoParty::send(alice_2sm_a, &alice_manager, b"Hello, Bob!", &rng).unwrap();
667
668        // Public key of "Bob" for the first round in Group A.
669        let bob_public_key_1 = alice_2sm_a.their_public_key;
670
671        let (bob_2sm_a, bob_manager, receive_1) =
672            LongTermTwoParty::receive(bob_2sm_a, bob_manager, message_1).unwrap();
673
674        let (_bob_2sm_a, message_2) =
675            LongTermTwoParty::send(bob_2sm_a, &bob_manager, b"Hello, Alice!", &rng).unwrap();
676        let (_alice_2sm_a, alice_manager, receive_2) =
677            LongTermTwoParty::receive(alice_2sm_a, alice_manager, message_2).unwrap();
678
679        assert_eq!(receive_1, b"Hello, Bob!");
680        assert_eq!(receive_2, b"Hello, Alice!");
681
682        // Sometime later they start another group B with the same long-term pre-keys.
683
684        let alice_2sm_b = LongTermTwoParty::init(bob_prekey_bundle);
685        let bob_2sm_b = LongTermTwoParty::init(alice_prekey_bundle);
686
687        // They start exchanging "secret messages" to each other.
688
689        let (alice_2sm_b, message_1) =
690            LongTermTwoParty::send(alice_2sm_b, &alice_manager, b"Hello, again, Bob!", &rng)
691                .unwrap();
692
693        // Public key of "Bob" for the first round in Group B.
694        let bob_public_key_2 = alice_2sm_b.their_public_key;
695
696        let (bob_2sm_b, bob_manager, receive_1) =
697            LongTermTwoParty::receive(bob_2sm_b, bob_manager, message_1).unwrap();
698
699        let (_bob_2sm_b, message_2) =
700            LongTermTwoParty::send(bob_2sm_b, &bob_manager, b"Hello, again, Alice!", &rng).unwrap();
701        let (_alice_2sm_b, _alice_manager, receive_2) =
702            LongTermTwoParty::receive(alice_2sm_b, alice_manager, message_2).unwrap();
703
704        assert_eq!(receive_1, b"Hello, again, Bob!");
705        assert_eq!(receive_2, b"Hello, again, Alice!");
706
707        // The keys for the first round should be different across groups.
708
709        assert_ne!(bob_public_key_1, bob_public_key_2);
710    }
711
712    #[test]
713    fn invalid_replayed_messages() {
714        let rng = Rng::from_seed([1; 32]);
715
716        // Alice generates their key material.
717
718        let alice_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
719        let alice_manager =
720            KeyManager::init_and_generate_prekey(&alice_identity_secret, Lifetime::default(), &rng)
721                .unwrap();
722
723        let (alice_manager, alice_prekey_bundle) =
724            KeyManager::generate_onetime_bundle(alice_manager, &rng).unwrap();
725
726        // Bob generates their key material.
727
728        let bob_identity_secret = SecretKey::from_bytes(rng.random_array().unwrap());
729        let bob_manager =
730            KeyManager::init_and_generate_prekey(&bob_identity_secret, Lifetime::default(), &rng)
731                .unwrap();
732
733        let (bob_manager, bob_prekey_bundle) =
734            KeyManager::generate_onetime_bundle(bob_manager, &rng).unwrap();
735
736        // Alice and Bob set up the 2SM protocol handlers for each other.
737
738        let alice_2sm = OneTimeTwoParty::init(bob_prekey_bundle);
739        let bob_2sm = OneTimeTwoParty::init(alice_prekey_bundle);
740
741        // Alice sends a message to Bob.
742
743        let (alice_2sm, message_1) =
744            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"Hello, Bob!", &rng).unwrap();
745        let (bob_2sm, bob_manager, _receive_1) =
746            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_1.clone()).unwrap();
747
748        // Bob receives the same message again.
749
750        let result = OneTimeTwoParty::receive(bob_2sm.clone(), bob_manager.clone(), message_1);
751        assert!(matches!(result, Err(TwoPartyError::PreKeyReuse)));
752
753        // Alice sends another message to Bob.
754
755        let (_alice_2sm, message_2) =
756            OneTimeTwoParty::send(alice_2sm, &alice_manager, b"Hello, again, Bob!", &rng).unwrap();
757        let (bob_2sm, bob_manager, _receive_2) =
758            OneTimeTwoParty::receive(bob_2sm, bob_manager, message_2.clone()).unwrap();
759
760        // Bob receives the same message again.
761
762        let result = OneTimeTwoParty::receive(bob_2sm, bob_manager, message_2);
763        assert!(matches!(result, Err(TwoPartyError::Hpke(_))));
764    }
765}