pub struct TwoParty<KMG, KB> { /* private fields */ }Expand description
Two-Party Secure Messaging (2SM) Key Agreement Protocol as specified in the paper “Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees” (2020).
2SM is used for key-agreement as part of the DCGKA protocol allowing all members to learn about the “seed” for establishing new secret state. 2SM is pair-wise between all members of an encrypted group. p2panda uses 2SM for both “data-” and “message encryption” schemes.
§Protocol
An initiator “Alice” of a 2SM session uses the pre-keys of “Bob” to send the first encrypted message using the X3DH protocol. This only takes place once and the pre-keys can be considered “used” afterwards (which is especially important for one-time pre-keys).
All subsequent messages sent between Alice and Bob are encrypted using the HPKE protocol. For each round the sender uses the previous keys for HPKE and generates and attaches to the payload a new key-pair for future rounds.
To avoid reusing public keys (which would make FS impossible), whenever a party sends a message, it also updates the other party’s public key. To do so, it sends a new secret key along with its message, then deletes its own copy, storing only the public key.
To accommodate for messages arriving “late”, the secret key is kept until it or a newer secret has been used. In the case of a newer secret being used, all “previous” secret keys will be dropped.
§Forward secrecy
During the initial 2SM “round” using X3DH the forward secrecy is defined by the lifetime of the used pre-keys. For strong security guarantees it is recommended to use one-time pre-keys. If this requirement can be relaxed it is possible to use long-term pre-keys, with a lifetime defined by the application.
Each subsequent 2SM HPKE round uses exactly one secret key, which is then dropped and replaced by a newly-generated key-pair. This gives the key-agreement protocol strong forward secrecy guarantees for each round, independent of the used pre-keys.
§Cost of key-agreements
To make a group aware of a new secret key we could encrypt the secret pairwise with public-key encryption (PKE) towards each member of the group, resulting in an O(n^2) overhead as every member needs to share their secret with every other. The paper proposes an alternative approach with 2SM where a member prepares the next encryption keys not only for themselves but also for the other party, resulting in a more optimal O(n) cost when rotating keys. This allows us to “heal” the group in less steps after a member is removed.
§Message Ordering
2SM assumes that all messages are received in the order they have been sent. The application or underlying networking protocol needs to handle ordering. This is handled for us by the DCGKA protocol (as specified in the paper) and causally-ordered, authenticated broadcast in p2panda itself.
Implementations§
Source§impl<KMG, KB> TwoParty<KMG, KB>
impl<KMG, KB> TwoParty<KMG, KB>
Sourcepub fn init(their_prekey_bundle: KB) -> TwoPartyState<KB>
pub fn init(their_prekey_bundle: KB) -> TwoPartyState<KB>
Initialise new 2SM state using the other party’s pre-key bundle.
Sourcepub fn send(
y: TwoPartyState<KB>,
y_manager: &KMG::State,
plaintext: &[u8],
rng: &Rng,
) -> Result<(TwoPartyState<KB>, TwoPartyMessage), TwoPartyError>
pub fn send( y: TwoPartyState<KB>, y_manager: &KMG::State, plaintext: &[u8], rng: &Rng, ) -> Result<(TwoPartyState<KB>, TwoPartyMessage), TwoPartyError>
Securely send a plaintext message to the other party.
Sourcepub fn receive(
y: TwoPartyState<KB>,
y_manager: KMG::State,
message: TwoPartyMessage,
) -> Result<(TwoPartyState<KB>, KMG::State, Vec<u8>), TwoPartyError>
pub fn receive( y: TwoPartyState<KB>, y_manager: KMG::State, message: TwoPartyMessage, ) -> Result<(TwoPartyState<KB>, KMG::State, Vec<u8>), TwoPartyError>
Handle receiving a secure message from the other party.