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(
113 default,
114 rename = "shared_history",
115 alias = "m.shared_history",
116 alias = "org.matrix.msc3061.shared_history"
117 )]
118 pub shared_history: bool,
119}
120
121impl ExportedRoomKey {
122 pub fn from_backed_up_room_key(
126 room_id: OwnedRoomId,
127 session_id: String,
128 room_key: BackedUpRoomKey,
129 ) -> Self {
130 let BackedUpRoomKey {
131 algorithm,
132 sender_key,
133 session_key,
134 sender_claimed_keys,
135 forwarding_curve25519_key_chain,
136 shared_history,
137 } = room_key;
138
139 Self {
140 algorithm,
141 room_id,
142 sender_key,
143 session_id,
144 session_key,
145 sender_claimed_keys,
146 forwarding_curve25519_key_chain,
147 shared_history,
148 }
149 }
150}
151
152impl RoomKeyExport for &ExportedRoomKey {
153 fn room_id(&self) -> &ruma::RoomId {
154 &self.room_id
155 }
156
157 fn session_id(&self) -> &str {
158 &self.session_id
159 }
160
161 fn sender_key(&self) -> Curve25519PublicKey {
162 self.sender_key
163 }
164}
165
166#[derive(Deserialize, Serialize)]
178#[allow(missing_debug_implementations)]
179pub struct BackedUpRoomKey {
180 pub algorithm: EventEncryptionAlgorithm,
182
183 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
185 pub sender_key: Curve25519PublicKey,
186
187 pub session_key: ExportedSessionKey,
189
190 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
192
193 #[serde(
196 default,
197 deserialize_with = "deserialize_curve_key_vec",
198 serialize_with = "serialize_curve_key_vec"
199 )]
200 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
201
202 #[serde(
208 default,
209 rename = "shared_history",
210 alias = "m.shared_history",
211 alias = "org.matrix.msc3061.shared_history"
212 )]
213 pub shared_history: bool,
214}
215
216impl TryFrom<ExportedRoomKey> for ForwardedRoomKeyContent {
217 type Error = SessionExportError;
218
219 fn try_from(room_key: ExportedRoomKey) -> Result<ForwardedRoomKeyContent, Self::Error> {
225 match room_key.algorithm {
226 EventEncryptionAlgorithm::MegolmV1AesSha2 => {
227 if let Some(SigningKey::Ed25519(claimed_ed25519_key)) =
235 room_key.sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519)
236 {
237 Ok(ForwardedRoomKeyContent::MegolmV1AesSha2(
238 ForwardedMegolmV1AesSha2Content {
239 room_id: room_key.room_id,
240 session_id: room_key.session_id,
241 session_key: room_key.session_key,
242 claimed_sender_key: room_key.sender_key,
243 claimed_ed25519_key: *claimed_ed25519_key,
244 forwarding_curve25519_key_chain: room_key
245 .forwarding_curve25519_key_chain
246 .clone(),
247 other: Default::default(),
248 }
249 .into(),
250 ))
251 } else {
252 Err(SessionExportError::MissingEd25519Key)
253 }
254 }
255 #[cfg(feature = "experimental-algorithms")]
256 EventEncryptionAlgorithm::MegolmV2AesSha2 => {
257 Ok(ForwardedRoomKeyContent::MegolmV2AesSha2(
258 ForwardedMegolmV2AesSha2Content {
259 room_id: room_key.room_id,
260 session_id: room_key.session_id,
261 session_key: room_key.session_key,
262 claimed_sender_key: room_key.sender_key,
263 claimed_signing_keys: room_key.sender_claimed_keys,
264 other: Default::default(),
265 }
266 .into(),
267 ))
268 }
269 _ => Err(SessionExportError::Algorithm(room_key.algorithm)),
270 }
271 }
272}
273
274impl From<ExportedRoomKey> for BackedUpRoomKey {
275 fn from(value: ExportedRoomKey) -> Self {
276 let ExportedRoomKey {
277 algorithm,
278 room_id: _,
279 sender_key,
280 session_id: _,
281 session_key,
282 sender_claimed_keys,
283 forwarding_curve25519_key_chain,
284 shared_history,
285 } = value;
286
287 Self {
288 algorithm,
289 sender_key,
290 session_key,
291 sender_claimed_keys,
292 forwarding_curve25519_key_chain,
293 shared_history,
294 }
295 }
296}
297
298impl TryFrom<ForwardedRoomKeyContent> for ExportedRoomKey {
299 type Error = SessionExportError;
300
301 fn try_from(forwarded_key: ForwardedRoomKeyContent) -> Result<Self, Self::Error> {
303 let algorithm = forwarded_key.algorithm();
304
305 match forwarded_key {
306 ForwardedRoomKeyContent::MegolmV1AesSha2(content) => {
307 let mut sender_claimed_keys = SigningKeys::new();
308 sender_claimed_keys
309 .insert(DeviceKeyAlgorithm::Ed25519, content.claimed_ed25519_key.into());
310
311 Ok(Self {
312 algorithm,
313 room_id: content.room_id,
314 session_id: content.session_id,
315 forwarding_curve25519_key_chain: content.forwarding_curve25519_key_chain,
316 sender_claimed_keys,
317 sender_key: content.claimed_sender_key,
318 session_key: content.session_key,
319 shared_history: false,
320 })
321 }
322 #[cfg(feature = "experimental-algorithms")]
323 ForwardedRoomKeyContent::MegolmV2AesSha2(content) => Ok(Self {
324 algorithm,
325 room_id: content.room_id,
326 session_id: content.session_id,
327 forwarding_curve25519_key_chain: Default::default(),
328 sender_claimed_keys: content.claimed_signing_keys,
329 sender_key: content.claimed_sender_key,
330 session_key: content.session_key,
331 shared_history: false,
332 }),
333 ForwardedRoomKeyContent::Unknown(c) => Err(SessionExportError::Algorithm(c.algorithm)),
334 }
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use serde_json::json;
341
342 use super::BackedUpRoomKey;
343
344 #[test]
345 fn test_deserialize_backed_up_key() {
346 let data = json!({
347 "algorithm": "m.megolm.v1.aes-sha2",
348 "room_id": "!room:id",
349 "sender_key": "FOvlmz18LLI3k/llCpqRoKT90+gFF8YhuL+v1YBXHlw",
350 "session_id": "/2K+V777vipCxPZ0gpY9qcpz1DYaXwuMRIu0UEP0Wa0",
351 "session_key": "AQAAAAAclzWVMeWBKH+B/WMowa3rb4ma3jEl6n5W4GCs9ue65CruzD3ihX+85pZ9hsV9Bf6fvhjp76WNRajoJYX0UIt7aosjmu0i+H+07hEQ0zqTKpVoSH0ykJ6stAMhdr6Q4uW5crBmdTTBIsqmoWsNJZKKoE2+ldYrZ1lrFeaJbjBIY/9ivle++74qQsT2dIKWPanKc9Q2Gl8LjESLtFBD9Fmt",
352 "sender_claimed_keys": {
353 "ed25519": "F4P7f1Z0RjbiZMgHk1xBCG3KC4/Ng9PmxLJ4hQ13sHA"
354 },
355 "forwarding_curve25519_key_chain": ["DBPC2zr6c9qimo9YRFK3RVr0Two/I6ODb9mbsToZN3Q", "bBc/qzZFOOKshMMT+i4gjS/gWPDoKfGmETs9yfw9430"]
356 });
357
358 let backed_up_room_key: BackedUpRoomKey = serde_json::from_value(data)
359 .expect("We should be able to deserialize the backed up room key.");
360 assert_eq!(
361 backed_up_room_key.forwarding_curve25519_key_chain.len(),
362 2,
363 "The number of forwarding Curve25519 chains should be two."
364 );
365 }
366}