From aff1e1d0a88c648fb6d6d946a5bc4703cacabfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 9 Sep 2020 12:47:28 +0200 Subject: [PATCH] crypto: Add key export methods for inbound group sessions. --- .../src/olm/group_sessions/inbound.rs | 42 ++++++++- .../src/olm/group_sessions/mod.rs | 85 +++++++++++++++++++ matrix_sdk_crypto/src/olm/mod.rs | 3 +- 3 files changed, 127 insertions(+), 3 deletions(-) diff --git a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs index 1942f18f..ce41675a 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, convert::TryInto, fmt, sync::Arc}; +use std::{ + collections::BTreeMap, + convert::{TryFrom, TryInto}, + fmt, + sync::Arc, +}; use matrix_sdk_common::{ events::{room::encrypted::EncryptedEventContent, AnySyncRoomEvent, SyncMessageEvent}, @@ -32,7 +37,7 @@ pub use olm_rs::{ utility::OlmUtility, }; -use super::GroupSessionKey; +use super::{ExportedGroupSessionKey, ExportedRoomKey, GroupSessionKey}; use crate::error::{EventError, MegolmResult}; /// Inbound group session. @@ -103,6 +108,39 @@ impl InboundGroupSession { } } + /// Export this session. + pub async fn export(&self) -> ExportedRoomKey { + self.export_at_index(self.first_known_index().await) + .await + .expect("Can't export at the first known index") + } + + /// Export this session at the given message index. + pub async fn export_at_index(&self, message_index: u32) -> Option { + let session_key = + ExportedGroupSessionKey(self.inner.lock().await.export(message_index).ok()?); + + let mut sender_claimed_keys: BTreeMap = BTreeMap::new(); + + sender_claimed_keys.insert(DeviceKeyAlgorithm::Ed25519, (&*self.signing_key).to_owned()); + + Some(ExportedRoomKey { + algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2, + room_id: (&*self.room_id).clone(), + sender_key: (&*self.sender_key).to_owned(), + session_id: self.session_id().to_owned(), + forwarding_curve25519_key_chain: self + .forwarding_chains + .lock() + .await + .as_ref() + .cloned() + .unwrap_or_default(), + sender_claimed_keys, + session_key, + }) + } + /// Restore a Session from a previously pickled string. /// /// Returns the restored group session or a `OlmGroupSessionError` if there diff --git a/matrix_sdk_crypto/src/olm/group_sessions/mod.rs b/matrix_sdk_crypto/src/olm/group_sessions/mod.rs index fae5080c..7f9ac026 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/mod.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/mod.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use matrix_sdk_common::{ + events::forwarded_room_key::ForwardedRoomKeyEventContent, + identifiers::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId}, +}; use serde::{Deserialize, Serialize}; +use std::{collections::BTreeMap, convert::TryInto}; use zeroize::Zeroize; mod inbound; @@ -27,6 +32,86 @@ pub use outbound::{EncryptionSettings, OutboundGroupSession}; #[zeroize(drop)] pub struct GroupSessionKey(pub String); +/// The exported version of an private session key of a group session. +/// Can be used to create a new inbound group session. +#[derive(Clone, Debug, Serialize, Deserialize, Zeroize)] +#[zeroize(drop)] +pub struct ExportedGroupSessionKey(pub String); + +/// An exported version of a `InboundGroupSession` +/// +/// This can be used to share the `InboundGroupSession` in an exported file. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ExportedRoomKey { + /// The encryption algorithm that the session uses. + pub algorithm: EventEncryptionAlgorithm, + + /// The room where the session is used. + pub room_id: RoomId, + + /// The Curve25519 key of the device which initiated the session originally. + pub sender_key: String, + + /// The ID of the session that the key is for. + pub session_id: String, + + /// The key for the session. + pub session_key: ExportedGroupSessionKey, + + /// The Ed25519 key of the device which initiated the session originally. + pub sender_claimed_keys: BTreeMap, + + /// Chain of Curve25519 keys through which this session was forwarded, via + /// m.forwarded_room_key events. + pub forwarding_curve25519_key_chain: Vec, +} + +impl TryInto for ExportedRoomKey { + type Error = (); + + fn try_into(self) -> Result { + if self.sender_claimed_keys.len() != 1 { + Err(()) + } else { + let (algorithm, claimed_key) = self.sender_claimed_keys.iter().next().ok_or(())?; + + if algorithm != &DeviceKeyAlgorithm::Ed25519 { + return Err(()); + } + + Ok(ForwardedRoomKeyEventContent { + algorithm: self.algorithm, + room_id: self.room_id, + sender_key: self.sender_key, + session_id: self.session_id, + session_key: self.session_key.0.clone(), + sender_claimed_ed25519_key: claimed_key.to_owned(), + forwarding_curve25519_key_chain: self.forwarding_curve25519_key_chain, + }) + } + } +} + +impl From for ExportedRoomKey { + fn from(forwarded_key: ForwardedRoomKeyEventContent) -> Self { + let mut sender_claimed_keys: BTreeMap = BTreeMap::new(); + sender_claimed_keys.insert( + DeviceKeyAlgorithm::Ed25519, + forwarded_key.sender_claimed_ed25519_key, + ); + + Self { + algorithm: forwarded_key.algorithm, + room_id: forwarded_key.room_id, + session_id: forwarded_key.session_id, + forwarding_curve25519_key_chain: forwarded_key.forwarding_curve25519_key_chain, + sender_claimed_keys, + sender_key: forwarded_key.sender_key, + session_key: ExportedGroupSessionKey(forwarded_key.session_key), + } + } +} + #[cfg(test)] mod test { use std::{ diff --git a/matrix_sdk_crypto/src/olm/mod.rs b/matrix_sdk_crypto/src/olm/mod.rs index c69293c5..05e6b874 100644 --- a/matrix_sdk_crypto/src/olm/mod.rs +++ b/matrix_sdk_crypto/src/olm/mod.rs @@ -24,7 +24,8 @@ mod utility; pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount}; pub use group_sessions::{ - EncryptionSettings, InboundGroupSession, InboundGroupSessionPickle, PickledInboundGroupSession, + EncryptionSettings, ExportedRoomKey, InboundGroupSession, InboundGroupSessionPickle, + PickledInboundGroupSession, }; pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession}; pub use olm_rs::PicklingMode;