crypto: Add key export methods for inbound group sessions.

master
Damir Jelić 2020-09-09 12:47:28 +02:00
parent 98f69aed41
commit aff1e1d0a8
3 changed files with 127 additions and 3 deletions

View File

@ -12,7 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // 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::{ use matrix_sdk_common::{
events::{room::encrypted::EncryptedEventContent, AnySyncRoomEvent, SyncMessageEvent}, events::{room::encrypted::EncryptedEventContent, AnySyncRoomEvent, SyncMessageEvent},
@ -32,7 +37,7 @@ pub use olm_rs::{
utility::OlmUtility, utility::OlmUtility,
}; };
use super::GroupSessionKey; use super::{ExportedGroupSessionKey, ExportedRoomKey, GroupSessionKey};
use crate::error::{EventError, MegolmResult}; use crate::error::{EventError, MegolmResult};
/// Inbound group session. /// 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<ExportedRoomKey> {
let session_key =
ExportedGroupSessionKey(self.inner.lock().await.export(message_index).ok()?);
let mut sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String> = 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. /// Restore a Session from a previously pickled string.
/// ///
/// Returns the restored group session or a `OlmGroupSessionError` if there /// Returns the restored group session or a `OlmGroupSessionError` if there

View File

@ -12,7 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use matrix_sdk_common::{
events::forwarded_room_key::ForwardedRoomKeyEventContent,
identifiers::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId},
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryInto};
use zeroize::Zeroize; use zeroize::Zeroize;
mod inbound; mod inbound;
@ -27,6 +32,86 @@ pub use outbound::{EncryptionSettings, OutboundGroupSession};
#[zeroize(drop)] #[zeroize(drop)]
pub struct GroupSessionKey(pub String); 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<DeviceKeyAlgorithm, String>,
/// Chain of Curve25519 keys through which this session was forwarded, via
/// m.forwarded_room_key events.
pub forwarding_curve25519_key_chain: Vec<String>,
}
impl TryInto<ForwardedRoomKeyEventContent> for ExportedRoomKey {
type Error = ();
fn try_into(self) -> Result<ForwardedRoomKeyEventContent, Self::Error> {
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<ForwardedRoomKeyEventContent> for ExportedRoomKey {
fn from(forwarded_key: ForwardedRoomKeyEventContent) -> Self {
let mut sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String> = 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)] #[cfg(test)]
mod test { mod test {
use std::{ use std::{

View File

@ -24,7 +24,8 @@ mod utility;
pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount}; pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount};
pub use group_sessions::{ pub use group_sessions::{
EncryptionSettings, InboundGroupSession, InboundGroupSessionPickle, PickledInboundGroupSession, EncryptionSettings, ExportedRoomKey, InboundGroupSession, InboundGroupSessionPickle,
PickledInboundGroupSession,
}; };
pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession}; pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession};
pub use olm_rs::PicklingMode; pub use olm_rs::PicklingMode;