matrix_sdk_crypto/olm/group_sessions/
mod.rs1use ruma::{DeviceKeyAlgorithm, OwnedRoomId};
16use serde::{Deserialize, Serialize};
17
18mod forwarder_data;
19mod inbound;
20mod outbound;
21mod sender_data;
22pub(crate) mod sender_data_finder;
23
24pub use forwarder_data::ForwarderData;
25pub use inbound::{InboundGroupSession, PickledInboundGroupSession};
26pub(crate) use outbound::ShareState;
27pub use outbound::{
28 EncryptionSettings, OutboundGroupSession, OutboundGroupSessionEncryptionResult,
29 PickledOutboundGroupSession, ShareInfo,
30};
31pub use sender_data::{KnownSenderData, SenderData, SenderDataType};
32use thiserror::Error;
33pub use vodozemac::megolm::{ExportedSessionKey, SessionKey};
34use vodozemac::{Curve25519PublicKey, megolm::SessionKeyDecodeError};
35
36#[cfg(feature = "experimental-algorithms")]
37use crate::types::events::forwarded_room_key::ForwardedMegolmV2AesSha2Content;
38use crate::types::{
39 EventEncryptionAlgorithm, RoomKeyExport, SigningKey, SigningKeys, deserialize_curve_key,
40 deserialize_curve_key_vec,
41 events::forwarded_room_key::{ForwardedMegolmV1AesSha2Content, ForwardedRoomKeyContent},
42 serialize_curve_key, serialize_curve_key_vec,
43};
44
45#[derive(Debug, Error)]
47pub enum SessionCreationError {
48 #[error("The provided algorithm is not supported: {0}")]
50 Algorithm(EventEncryptionAlgorithm),
51 #[error(transparent)]
53 Decode(#[from] SessionKeyDecodeError),
54}
55
56#[derive(Debug, Error)]
61pub enum SessionExportError {
62 #[error("The provided algorithm is not supported: {0}")]
64 Algorithm(EventEncryptionAlgorithm),
65 #[error("The provided room key export is missing a claimed Ed25519 sender key")]
67 MissingEd25519Key,
68}
69
70#[derive(Deserialize, Serialize)]
76#[allow(missing_debug_implementations)]
77pub struct ExportedRoomKey {
78 pub algorithm: EventEncryptionAlgorithm,
80
81 pub room_id: OwnedRoomId,
83
84 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
86 pub sender_key: Curve25519PublicKey,
87
88 pub session_id: String,
90
91 pub session_key: ExportedSessionKey,
93
94 #[serde(default)]
96 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
97
98 #[serde(
101 default,
102 deserialize_with = "deserialize_curve_key_vec",
103 serialize_with = "serialize_curve_key_vec"
104 )]
105 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
106
107 #[serde(default, rename = "org.matrix.msc3061.shared_history")]
113 pub shared_history: bool,
114}
115
116impl ExportedRoomKey {
117 pub fn from_backed_up_room_key(
121 room_id: OwnedRoomId,
122 session_id: String,
123 room_key: BackedUpRoomKey,
124 ) -> Self {
125 let BackedUpRoomKey {
126 algorithm,
127 sender_key,
128 session_key,
129 sender_claimed_keys,
130 forwarding_curve25519_key_chain,
131 shared_history,
132 } = room_key;
133
134 Self {
135 algorithm,
136 room_id,
137 sender_key,
138 session_id,
139 session_key,
140 sender_claimed_keys,
141 forwarding_curve25519_key_chain,
142 shared_history,
143 }
144 }
145}
146
147impl RoomKeyExport for &ExportedRoomKey {
148 fn room_id(&self) -> &ruma::RoomId {
149 &self.room_id
150 }
151
152 fn session_id(&self) -> &str {
153 &self.session_id
154 }
155
156 fn sender_key(&self) -> Curve25519PublicKey {
157 self.sender_key
158 }
159}
160
161#[derive(Deserialize, Serialize)]
170#[allow(missing_debug_implementations)]
171pub struct BackedUpRoomKey {
172 pub algorithm: EventEncryptionAlgorithm,
174
175 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
177 pub sender_key: Curve25519PublicKey,
178
179 pub session_key: ExportedSessionKey,
181
182 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
184
185 #[serde(
188 default,
189 deserialize_with = "deserialize_curve_key_vec",
190 serialize_with = "serialize_curve_key_vec"
191 )]
192 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
193
194 #[serde(default, rename = "org.matrix.msc3061.shared_history")]
200 pub shared_history: bool,
201}
202
203impl TryFrom<ExportedRoomKey> for ForwardedRoomKeyContent {
204 type Error = SessionExportError;
205
206 fn try_from(room_key: ExportedRoomKey) -> Result<ForwardedRoomKeyContent, Self::Error> {
212 match room_key.algorithm {
213 EventEncryptionAlgorithm::MegolmV1AesSha2 => {
214 if let Some(SigningKey::Ed25519(claimed_ed25519_key)) =
221 room_key.sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519)
222 {
223 Ok(ForwardedRoomKeyContent::MegolmV1AesSha2(
224 ForwardedMegolmV1AesSha2Content {
225 room_id: room_key.room_id,
226 session_id: room_key.session_id,
227 session_key: room_key.session_key,
228 claimed_sender_key: room_key.sender_key,
229 claimed_ed25519_key: *claimed_ed25519_key,
230 forwarding_curve25519_key_chain: room_key
231 .forwarding_curve25519_key_chain
232 .clone(),
233 other: Default::default(),
234 }
235 .into(),
236 ))
237 } else {
238 Err(SessionExportError::MissingEd25519Key)
239 }
240 }
241 #[cfg(feature = "experimental-algorithms")]
242 EventEncryptionAlgorithm::MegolmV2AesSha2 => {
243 Ok(ForwardedRoomKeyContent::MegolmV2AesSha2(
244 ForwardedMegolmV2AesSha2Content {
245 room_id: room_key.room_id,
246 session_id: room_key.session_id,
247 session_key: room_key.session_key,
248 claimed_sender_key: room_key.sender_key,
249 claimed_signing_keys: room_key.sender_claimed_keys,
250 other: Default::default(),
251 }
252 .into(),
253 ))
254 }
255 _ => Err(SessionExportError::Algorithm(room_key.algorithm)),
256 }
257 }
258}
259
260impl From<ExportedRoomKey> for BackedUpRoomKey {
261 fn from(value: ExportedRoomKey) -> Self {
262 let ExportedRoomKey {
263 algorithm,
264 room_id: _,
265 sender_key,
266 session_id: _,
267 session_key,
268 sender_claimed_keys,
269 forwarding_curve25519_key_chain,
270 shared_history,
271 } = value;
272
273 Self {
274 algorithm,
275 sender_key,
276 session_key,
277 sender_claimed_keys,
278 forwarding_curve25519_key_chain,
279 shared_history,
280 }
281 }
282}
283
284impl TryFrom<ForwardedRoomKeyContent> for ExportedRoomKey {
285 type Error = SessionExportError;
286
287 fn try_from(forwarded_key: ForwardedRoomKeyContent) -> Result<Self, Self::Error> {
289 let algorithm = forwarded_key.algorithm();
290
291 match forwarded_key {
292 ForwardedRoomKeyContent::MegolmV1AesSha2(content) => {
293 let mut sender_claimed_keys = SigningKeys::new();
294 sender_claimed_keys
295 .insert(DeviceKeyAlgorithm::Ed25519, content.claimed_ed25519_key.into());
296
297 Ok(Self {
298 algorithm,
299 room_id: content.room_id,
300 session_id: content.session_id,
301 forwarding_curve25519_key_chain: content.forwarding_curve25519_key_chain,
302 sender_claimed_keys,
303 sender_key: content.claimed_sender_key,
304 session_key: content.session_key,
305 shared_history: false,
306 })
307 }
308 #[cfg(feature = "experimental-algorithms")]
309 ForwardedRoomKeyContent::MegolmV2AesSha2(content) => Ok(Self {
310 algorithm,
311 room_id: content.room_id,
312 session_id: content.session_id,
313 forwarding_curve25519_key_chain: Default::default(),
314 sender_claimed_keys: content.claimed_signing_keys,
315 sender_key: content.claimed_sender_key,
316 session_key: content.session_key,
317 shared_history: false,
318 }),
319 ForwardedRoomKeyContent::Unknown(c) => Err(SessionExportError::Algorithm(c.algorithm)),
320 }
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use serde_json::json;
327
328 use super::BackedUpRoomKey;
329
330 #[test]
331 fn test_deserialize_backed_up_key() {
332 let data = json!({
333 "algorithm": "m.megolm.v1.aes-sha2",
334 "room_id": "!room:id",
335 "sender_key": "FOvlmz18LLI3k/llCpqRoKT90+gFF8YhuL+v1YBXHlw",
336 "session_id": "/2K+V777vipCxPZ0gpY9qcpz1DYaXwuMRIu0UEP0Wa0",
337 "session_key": "AQAAAAAclzWVMeWBKH+B/WMowa3rb4ma3jEl6n5W4GCs9ue65CruzD3ihX+85pZ9hsV9Bf6fvhjp76WNRajoJYX0UIt7aosjmu0i+H+07hEQ0zqTKpVoSH0ykJ6stAMhdr6Q4uW5crBmdTTBIsqmoWsNJZKKoE2+ldYrZ1lrFeaJbjBIY/9ivle++74qQsT2dIKWPanKc9Q2Gl8LjESLtFBD9Fmt",
338 "sender_claimed_keys": {
339 "ed25519": "F4P7f1Z0RjbiZMgHk1xBCG3KC4/Ng9PmxLJ4hQ13sHA"
340 },
341 "forwarding_curve25519_key_chain": ["DBPC2zr6c9qimo9YRFK3RVr0Two/I6ODb9mbsToZN3Q", "bBc/qzZFOOKshMMT+i4gjS/gWPDoKfGmETs9yfw9430"]
342 });
343
344 let backed_up_room_key: BackedUpRoomKey = serde_json::from_value(data)
345 .expect("We should be able to deserialize the backed up room key.");
346 assert_eq!(
347 backed_up_room_key.forwarding_curve25519_key_chain.len(),
348 2,
349 "The number of forwarding Curve25519 chains should be two."
350 );
351 }
352}